Merge "Import translations. DO NOT MERGE ANYWHERE" into androidx-main
diff --git a/ads/ads-identifier-provider/integration-tests/testapp/lint-baseline.xml b/ads/ads-identifier-provider/integration-tests/testapp/lint-baseline.xml
index 7683bde..0160194 100644
--- a/ads/ads-identifier-provider/integration-tests/testapp/lint-baseline.xml
+++ b/ads/ads-identifier-provider/integration-tests/testapp/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<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="UnknownNullness"
diff --git a/annotation/annotation/lint-baseline.xml b/annotation/annotation/lint-baseline.xml
deleted file mode 100644
index a148b58..0000000
--- a/annotation/annotation/lint-baseline.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?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="SupportAnnotationUsage"
- message="Do not use `@java.lang.annotation.Target` here; it will cause the annotation to not be allowed on **any** element types from Java"
- errorLine1="@java.lang.annotation.Target("
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/annotation/Keep.kt"/>
- </issue>
-
- <issue
- id="SupportAnnotationUsage"
- message="Do not use `@java.lang.annotation.Target` here; it will cause the annotation to not be allowed on **any** element types from Java"
- errorLine1="@java.lang.annotation.Target("
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/annotation/NonNull.kt"/>
- </issue>
-
- <issue
- id="SupportAnnotationUsage"
- message="Do not use `@java.lang.annotation.Target` here; it will cause the annotation to not be allowed on **any** element types from Java"
- errorLine1="@java.lang.annotation.Target(METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE)"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/annotation/Nullable.kt"/>
- </issue>
-
- <issue
- id="SupportAnnotationUsage"
- message="Do not use `@java.lang.annotation.Target` here; it will cause the annotation to not be allowed on **any** element types from Java"
- errorLine1="@java.lang.annotation.Target(TYPE, METHOD, CONSTRUCTOR, FIELD, PACKAGE)"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/annotation/RequiresApi.kt"/>
- </issue>
-
- <issue
- id="SupportAnnotationUsage"
- message="Do not use `@java.lang.annotation.Target` here; it will cause the annotation to not be allowed on **any** element types from Java"
- errorLine1="@java.lang.annotation.Target("
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/annotation/RestrictTo.kt"/>
- </issue>
-
-</issues>
diff --git a/appcompat/appcompat/src/main/res/values-ro/strings.xml b/appcompat/appcompat/src/main/res/values-ro/strings.xml
index 037261b..d5bde8f 100644
--- a/appcompat/appcompat/src/main/res/values-ro/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-ro/strings.xml
@@ -17,8 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="abc_action_mode_done" msgid="4692188335987374352">"Gata"</string>
- <string name="abc_action_bar_home_description" msgid="5976598919945601918">"Navigați la ecranul de pornire"</string>
- <string name="abc_action_bar_up_description" msgid="8388173803310557296">"Navigați în sus"</string>
+ <string name="abc_action_bar_home_description" msgid="5976598919945601918">"Navighează la ecranul de pornire"</string>
+ <string name="abc_action_bar_up_description" msgid="8388173803310557296">"Navighează în sus"</string>
<string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"Mai multe opțiuni"</string>
<string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"Restrânge"</string>
<string name="abc_searchview_description_search" msgid="3417662926640357176">"Caută"</string>
diff --git a/appsearch/appsearch/lint-baseline.xml b/appsearch/appsearch/lint-baseline.xml
index 9eebc3d..fa994f2 100644
--- a/appsearch/appsearch/lint-baseline.xml
+++ b/appsearch/appsearch/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
<issue
id="SupportAnnotationUsage"
diff --git a/arch/core/core-testing/lint-baseline.xml b/arch/core/core-testing/lint-baseline.xml
index e4e77e4..0004e63 100644
--- a/arch/core/core-testing/lint-baseline.xml
+++ b/arch/core/core-testing/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<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="UnknownNullness"
diff --git a/buildSrc/apply/applyAndroidXLayoutlibImplPlugin.gradle b/buildSrc/apply/applyAndroidXLayoutlibImplPlugin.gradle
new file mode 100644
index 0000000..c89f0f4
--- /dev/null
+++ b/buildSrc/apply/applyAndroidXLayoutlibImplPlugin.gradle
@@ -0,0 +1,9 @@
+import androidx.build.layoutlib.AndroidXLayoutlibImplPlugin
+
+buildscript {
+ dependencies {
+ classpath(project.files("${project.rootProject.ext["buildSrcOut"]}/private/build/libs/private.jar"))
+ }
+}
+
+apply plugin: AndroidXLayoutlibImplPlugin
diff --git a/buildSrc/apply/applyAndroidXPaparazziImplPlugin.gradle b/buildSrc/apply/applyAndroidXPaparazziImplPlugin.gradle
deleted file mode 100644
index ece0f79..0000000
--- a/buildSrc/apply/applyAndroidXPaparazziImplPlugin.gradle
+++ /dev/null
@@ -1,9 +0,0 @@
-import androidx.build.paparazzi.AndroidXPaparazziImplPlugin
-
-buildscript {
- dependencies {
- classpath(project.files("${project.rootProject.ext["buildSrcOut"]}/private/build/libs/private.jar"))
- }
-}
-
-apply plugin: AndroidXPaparazziImplPlugin
diff --git a/buildSrc/plugins/src/main/kotlin/androidx/build/paparazzi/AndroidXPaparazziPlugin.kt b/buildSrc/plugins/src/main/kotlin/androidx/build/AndroidXLayoutlibPlugin.kt
similarity index 86%
rename from buildSrc/plugins/src/main/kotlin/androidx/build/paparazzi/AndroidXPaparazziPlugin.kt
rename to buildSrc/plugins/src/main/kotlin/androidx/build/AndroidXLayoutlibPlugin.kt
index 98fc29f..f6cd2a5 100644
--- a/buildSrc/plugins/src/main/kotlin/androidx/build/paparazzi/AndroidXPaparazziPlugin.kt
+++ b/buildSrc/plugins/src/main/kotlin/androidx/build/AndroidXLayoutlibPlugin.kt
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-package androidx.build.paparazzi
+package androidx.build
-import androidx.build.getSupportRootFolder
import org.gradle.api.Plugin
import org.gradle.api.Project
@@ -25,12 +24,12 @@
*
* The actual implementation is in AndroidXPaparazziImplPlugin.
*/
-class AndroidXPaparazziPlugin : Plugin<Project> {
+class AndroidXLayoutlibPlugin : Plugin<Project> {
override fun apply(project: Project) {
val supportRoot = project.getSupportRootFolder()
project.apply(
mapOf(
- "from" to "$supportRoot/buildSrc/apply/applyAndroidXPaparazziImplPlugin.gradle"
+ "from" to "$supportRoot/buildSrc/apply/applyAndroidXLayoutlibImplPlugin.gradle"
)
)
}
diff --git a/buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXPaparazziPlugin.properties b/buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXLayoutlibPlugin.properties
similarity index 89%
rename from buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXPaparazziPlugin.properties
rename to buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXLayoutlibPlugin.properties
index b95a130..9d8b362 100644
--- a/buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXPaparazziPlugin.properties
+++ b/buildSrc/plugins/src/main/resources/META-INF/gradle-plugins/AndroidXLayoutlibPlugin.properties
@@ -14,4 +14,4 @@
# limitations under the License.
#
-implementation-class=androidx.build.paparazzi.AndroidXPaparazziPlugin
+implementation-class=androidx.build.AndroidXLayoutlibPlugin
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/paparazzi/AndroidXPaparazziImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/layoutlib/AndroidXLayoutlibImplPlugin.kt
similarity index 96%
rename from buildSrc/private/src/main/kotlin/androidx/build/paparazzi/AndroidXPaparazziImplPlugin.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/layoutlib/AndroidXLayoutlibImplPlugin.kt
index 778810b..f4bff37 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/paparazzi/AndroidXPaparazziImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/layoutlib/AndroidXLayoutlibImplPlugin.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.build.paparazzi
+package androidx.build.layoutlib
import androidx.build.OperatingSystem
import androidx.build.SupportConfig.COMPILE_SDK_VERSION
@@ -38,7 +38,7 @@
/**
* Configures screenshot testing using Paparazzi for AndroidX projects.
*/
-class AndroidXPaparazziImplPlugin : Plugin<Project> {
+class AndroidXLayoutlibImplPlugin : Plugin<Project> {
override fun apply(project: Project) {
val paparazziNative = project.createUnzippedPaparazziNativeDependency()
project.afterEvaluate {
@@ -121,7 +121,7 @@
private companion object {
/** Package name of the test library, used to namespace system properties */
- const val PACKAGE_NAME = "androidx.test.screenshot.paparazzi"
+ const val PACKAGE_NAME = "androidx.test.screenshot.layoutlib"
/** Artifact type attribute for unzipped Paparazzi layoutlib unzipped artifacts */
const val UNZIPPED_PAPARAZZI_NATIVE = "unzipped-paparazzi-native"
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/paparazzi/UnzipPaparazziNativeTransform.kt b/buildSrc/private/src/main/kotlin/androidx/build/layoutlib/UnzipPaparazziNativeTransform.kt
similarity index 98%
rename from buildSrc/private/src/main/kotlin/androidx/build/paparazzi/UnzipPaparazziNativeTransform.kt
rename to buildSrc/private/src/main/kotlin/androidx/build/layoutlib/UnzipPaparazziNativeTransform.kt
index 0af7ef7..5ba6ef5 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/paparazzi/UnzipPaparazziNativeTransform.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/layoutlib/UnzipPaparazziNativeTransform.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.build.paparazzi
+package androidx.build.layoutlib
import java.util.zip.ZipInputStream
import org.gradle.api.artifacts.transform.CacheableTransform
diff --git a/buildSrc/private/src/main/resources/META-INF/gradle-plugins/AndroidXPaparazziImplPlugin.properties b/buildSrc/private/src/main/resources/META-INF/gradle-plugins/AndroidXPaparazziImplPlugin.properties
index 0ea8b07..eacaf4a 100644
--- a/buildSrc/private/src/main/resources/META-INF/gradle-plugins/AndroidXPaparazziImplPlugin.properties
+++ b/buildSrc/private/src/main/resources/META-INF/gradle-plugins/AndroidXPaparazziImplPlugin.properties
@@ -14,4 +14,4 @@
# limitations under the License.
#
-implementation-class=androidx.build.paparazzi.AndroidXPaparazziImplPlugin
+implementation-class=androidx.build.layoutlib.AndroidXLayoutlibImplPlugin
diff --git a/camera/camera-camera2-pipe-integration/lint-baseline.xml b/camera/camera-camera2-pipe-integration/lint-baseline.xml
index acec75e..76fc250 100644
--- a/camera/camera-camera2-pipe-integration/lint-baseline.xml
+++ b/camera/camera-camera2-pipe-integration/lint-baseline.xml
@@ -4,8 +4,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"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ errorLine1=" @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal val requestListener:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt"/>
</issue>
diff --git a/car/app/app-samples/navigation/common/lint-baseline.xml b/car/app/app-samples/navigation/common/lint-baseline.xml
index f493425..bbc7529 100644
--- a/car/app/app-samples/navigation/common/lint-baseline.xml
+++ b/car/app/app-samples/navigation/common/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<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="ClassVerificationFailure"
diff --git a/car/app/app/api/public_plus_experimental_1.3.0-beta02.txt b/car/app/app/api/public_plus_experimental_1.3.0-beta02.txt
index 108129b..514019a 100644
--- a/car/app/app/api/public_plus_experimental_1.3.0-beta02.txt
+++ b/car/app/app/api/public_plus_experimental_1.3.0-beta02.txt
@@ -841,6 +841,44 @@
}
+package androidx.car.app.messaging.model {
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public class CarMessage {
+ method public androidx.car.app.model.CarText getBody();
+ method public long getReceivedTimeEpochMillis();
+ method public androidx.core.app.Person getSender();
+ method public boolean isRead();
+ }
+
+ public static final class CarMessage.Builder {
+ ctor public CarMessage.Builder();
+ method public androidx.car.app.messaging.model.CarMessage build();
+ method public androidx.car.app.messaging.model.CarMessage.Builder setBody(androidx.car.app.model.CarText);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setRead(boolean);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setReceivedTimeEpochMillis(long);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setSender(androidx.core.app.Person);
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public class ConversationItem implements androidx.car.app.model.Item {
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public String getId();
+ method public java.util.List<androidx.car.app.messaging.model.CarMessage!> getMessages();
+ method public androidx.car.app.model.CarText getTitle();
+ method public boolean isGroupConversation();
+ }
+
+ public static final class ConversationItem.Builder {
+ ctor public ConversationItem.Builder();
+ method public androidx.car.app.messaging.model.ConversationItem build();
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setGroupConversation(boolean);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setId(String);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setMessages(java.util.List<androidx.car.app.messaging.model.CarMessage!>);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setTitle(androidx.car.app.model.CarText);
+ }
+
+}
+
package androidx.car.app.model {
@androidx.car.app.annotations.CarProtocol public final class Action {
diff --git a/car/app/app/api/public_plus_experimental_current.txt b/car/app/app/api/public_plus_experimental_current.txt
index 108129b..514019a 100644
--- a/car/app/app/api/public_plus_experimental_current.txt
+++ b/car/app/app/api/public_plus_experimental_current.txt
@@ -841,6 +841,44 @@
}
+package androidx.car.app.messaging.model {
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public class CarMessage {
+ method public androidx.car.app.model.CarText getBody();
+ method public long getReceivedTimeEpochMillis();
+ method public androidx.core.app.Person getSender();
+ method public boolean isRead();
+ }
+
+ public static final class CarMessage.Builder {
+ ctor public CarMessage.Builder();
+ method public androidx.car.app.messaging.model.CarMessage build();
+ method public androidx.car.app.messaging.model.CarMessage.Builder setBody(androidx.car.app.model.CarText);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setRead(boolean);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setReceivedTimeEpochMillis(long);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setSender(androidx.core.app.Person);
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public class ConversationItem implements androidx.car.app.model.Item {
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public String getId();
+ method public java.util.List<androidx.car.app.messaging.model.CarMessage!> getMessages();
+ method public androidx.car.app.model.CarText getTitle();
+ method public boolean isGroupConversation();
+ }
+
+ public static final class ConversationItem.Builder {
+ ctor public ConversationItem.Builder();
+ method public androidx.car.app.messaging.model.ConversationItem build();
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setGroupConversation(boolean);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setId(String);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setMessages(java.util.List<androidx.car.app.messaging.model.CarMessage!>);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setTitle(androidx.car.app.model.CarText);
+ }
+
+}
+
package androidx.car.app.model {
@androidx.car.app.annotations.CarProtocol public final class Action {
diff --git a/car/app/app/src/main/java/androidx/car/app/messaging/model/CarMessage.java b/car/app/app/src/main/java/androidx/car/app/messaging/model/CarMessage.java
new file mode 100644
index 0000000..f5bd59f
--- /dev/null
+++ b/car/app/app/src/main/java/androidx/car/app/messaging/model/CarMessage.java
@@ -0,0 +1,123 @@
+/*
+ * 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.car.app.messaging.model;
+
+import static java.util.Objects.requireNonNull;
+
+import androidx.annotation.Keep;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.car.app.annotations.CarProtocol;
+import androidx.car.app.annotations.ExperimentalCarApi;
+import androidx.car.app.annotations.RequiresCarApi;
+import androidx.car.app.model.CarText;
+import androidx.core.app.Person;
+
+/** Represents a single message in a {@link ConversationItem} */
+@ExperimentalCarApi
+@CarProtocol
+@RequiresCarApi(6)
+public class CarMessage {
+ @Keep
+ @NonNull
+ private final Person mSender;
+
+ @Keep
+ @NonNull
+ private final CarText mBody;
+ @Keep
+ private final long mReceivedTimeEpochMillis;
+
+ @Keep
+ private final boolean mIsRead;
+
+ CarMessage(@NonNull Builder builder) {
+ this.mSender = requireNonNull(builder.mSender);
+ this.mBody = requireNonNull(builder.mBody);
+ this.mReceivedTimeEpochMillis = builder.mReceivedTimeEpochMillis;
+ this.mIsRead = builder.mIsRead;
+ }
+
+ /** Default constructor for serialization. */
+ private CarMessage() {
+ this.mSender = new Person.Builder().setName("").build();
+ this.mBody = new CarText.Builder("").build();
+ this.mReceivedTimeEpochMillis = 0;
+ this.mIsRead = false;
+ }
+
+
+ /** Returns a {@link Person} representing the message sender */
+ @NonNull public Person getSender() {
+ return mSender;
+ }
+
+ /** Returns a {@link CarText} representing the message body */
+ @NonNull
+ public CarText getBody() {
+ return mBody;
+ }
+
+ /** Returns a {@code long} representing the message timestamp (in epoch millis) */
+ public long getReceivedTimeEpochMillis() {
+ return mReceivedTimeEpochMillis;
+ }
+
+ /** Returns a {@link boolean}, indicating whether the message has been read */
+ public boolean isRead() {
+ return mIsRead;
+ }
+
+ /** A builder for {@link CarMessage} */
+ public static final class Builder {
+ @Nullable
+ Person mSender;
+ @Nullable
+ CarText mBody;
+ long mReceivedTimeEpochMillis;
+ boolean mIsRead;
+
+ /** Sets a {@link Person} representing the message sender */
+ public @NonNull Builder setSender(@NonNull Person sender) {
+ mSender = sender;
+ return this;
+ }
+
+ /** Sets a {@link CarText} representing the message body */
+ public @NonNull Builder setBody(@NonNull CarText body) {
+ mBody = body;
+ return this;
+ }
+
+ /** Sets a {@code long} representing the message timestamp (in epoch millis) */
+ public @NonNull Builder setReceivedTimeEpochMillis(long receivedTimeEpochMillis) {
+ mReceivedTimeEpochMillis = receivedTimeEpochMillis;
+ return this;
+ }
+
+ /** Sets a {@link boolean}, indicating whether the message has been read */
+ public @NonNull Builder setRead(boolean isRead) {
+ mIsRead = isRead;
+ return this;
+ }
+
+ /** Returns a new {@link CarMessage} instance defined by this builder */
+ public @NonNull CarMessage build() {
+ return new CarMessage(this);
+ }
+ }
+}
diff --git a/car/app/app/src/main/java/androidx/car/app/messaging/model/ConversationItem.java b/car/app/app/src/main/java/androidx/car/app/messaging/model/ConversationItem.java
new file mode 100644
index 0000000..42eeeba
--- /dev/null
+++ b/car/app/app/src/main/java/androidx/car/app/messaging/model/ConversationItem.java
@@ -0,0 +1,160 @@
+/*
+ * 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.car.app.messaging.model;
+
+import static java.util.Objects.requireNonNull;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.car.app.annotations.CarProtocol;
+import androidx.car.app.annotations.ExperimentalCarApi;
+import androidx.car.app.annotations.RequiresCarApi;
+import androidx.car.app.model.CarIcon;
+import androidx.car.app.model.CarText;
+import androidx.car.app.model.Item;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Represents a conversation */
+@ExperimentalCarApi
+@CarProtocol
+@RequiresCarApi(6)
+public class ConversationItem implements Item {
+ @NonNull private final String mId;
+ @NonNull private final CarText mTitle;
+ @Nullable
+ private final CarIcon mIcon;
+ private final boolean mIsGroupConversation;
+ @NonNull private final List<CarMessage> mMessages;
+
+ ConversationItem(@NonNull Builder builder) {
+ this.mId = requireNonNull(builder.mId);
+ this.mTitle = requireNonNull(builder.mTitle);
+ this.mIcon = builder.mIcon;
+ this.mIsGroupConversation = builder.mIsGroupConversation;
+ this.mMessages = requireNonNull(builder.mMessages);
+ }
+
+ /** Default constructor for serialization. */
+ private ConversationItem() {
+ mId = "";
+ mTitle = new CarText.Builder("").build();
+ mIcon = null;
+ mIsGroupConversation = false;
+ mMessages = new ArrayList<>();
+ }
+
+ /**
+ * Returns a unique identifier for the conversation
+ *
+ * @see Builder#setId
+ */
+ public @NonNull String getId() {
+ return mId;
+ }
+
+ /** Returns the title of the conversation */
+ public @NonNull CarText getTitle() {
+ return mTitle;
+ }
+
+ /** Returns a {@link CarIcon} for the conversation, or {@code null} if not set */
+ public @Nullable CarIcon getIcon() {
+ return mIcon;
+ }
+
+ /**
+ * Returns whether this conversation involves 3+ participants (a "group" conversation)
+ *
+ * @see Builder#setGroupConversation(boolean)
+ */
+ public boolean isGroupConversation() {
+ return mIsGroupConversation;
+ }
+
+ /** Returns a list of messages for this {@link ConversationItem} */
+ public @NonNull List<CarMessage> getMessages() {
+ return mMessages;
+ }
+
+ /** A builder for {@link ConversationItem} */
+ public static final class Builder {
+ @Nullable
+ String mId;
+ @Nullable
+ CarText mTitle;
+ @Nullable
+ CarIcon mIcon;
+ boolean mIsGroupConversation;
+ @Nullable
+ List<CarMessage> mMessages;
+
+ /**
+ * Specifies a unique identifier for the conversation
+ *
+ * <p> IDs may be used for a variety of purposes, including...
+ * <ul>
+ * <li> Distinguishing new {@link ConversationItem}s from updated
+ * {@link ConversationItem}s in the UI, when data is refreshed
+ * <li> Identifying {@link ConversationItem}s in "mark as read" / "reply" callbacks
+ * </ul>
+ */
+ public @NonNull Builder setId(@NonNull String id) {
+ mId = id;
+ return this;
+ }
+
+ /** Sets the title of the conversation */
+ public @NonNull Builder setTitle(@NonNull CarText title) {
+ mTitle = title;
+ return this;
+ }
+
+ /** Sets a {@link CarIcon} for the conversation */
+ public @NonNull Builder setIcon(@NonNull CarIcon icon) {
+ mIcon = icon;
+ return this;
+ }
+
+ /**
+ * Specifies whether this conversation involves 3+ participants (a "group" conversation)
+ *
+ * <p> If unspecified, conversations are assumed to have exactly two participants (a "1:1"
+ * conversation)
+ *
+ * <p> UX presentation may differ slightly between group and 1:1 conversations. As a
+ * historical example, message readout may include sender names for group conversations, but
+ * omit them for 1:1 conversations.
+ */
+ public @NonNull Builder setGroupConversation(boolean isGroupConversation) {
+ mIsGroupConversation = isGroupConversation;
+ return this;
+ }
+
+ /** Specifies a list of messages for the conversation */
+ public @NonNull Builder setMessages(@NonNull List<CarMessage> messages) {
+ mMessages = messages;
+ return this;
+ }
+
+ /** Returns a new {@link ConversationItem} instance defined by this builder */
+ public @NonNull ConversationItem build() {
+ return new ConversationItem(this);
+ }
+ }
+}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyGridPrefetcherTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyGridPrefetcherTest.kt
index 0c54c3c1..3c9694c 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyGridPrefetcherTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyGridPrefetcherTest.kt
@@ -33,6 +33,7 @@
import androidx.compose.ui.unit.dp
import androidx.test.filters.LargeTest
import com.google.common.truth.Truth
+import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
@@ -60,7 +61,7 @@
@Test
fun notPrefetchingForwardInitially() {
- composeList()
+ composeGrid()
rule.onNodeWithTag("4")
.assertDoesNotExist()
@@ -68,7 +69,7 @@
@Test
fun notPrefetchingBackwardInitially() {
- composeList(firstItem = 4)
+ composeGrid(firstItem = 4)
rule.onNodeWithTag("0")
.assertDoesNotExist()
@@ -76,7 +77,7 @@
@Test
fun prefetchingForwardAfterSmallScroll() {
- composeList()
+ composeGrid()
rule.runOnIdle {
runBlocking {
@@ -96,7 +97,7 @@
@Test
fun prefetchingBackwardAfterSmallScroll() {
- composeList(firstItem = 4, itemOffset = 10)
+ composeGrid(firstItem = 4, itemOffset = 10)
rule.runOnIdle {
runBlocking {
@@ -116,7 +117,7 @@
@Test
fun prefetchingForwardAndBackward() {
- composeList(firstItem = 2)
+ composeGrid(firstItem = 2)
rule.runOnIdle {
runBlocking {
@@ -152,7 +153,7 @@
@Test
fun prefetchingForwardTwice() {
- composeList()
+ composeGrid()
rule.runOnIdle {
runBlocking {
@@ -181,7 +182,7 @@
@Test
fun prefetchingBackwardTwice() {
- composeList(firstItem = 8)
+ composeGrid(firstItem = 8)
rule.runOnIdle {
runBlocking {
@@ -212,7 +213,7 @@
@Test
fun prefetchingForwardAndBackwardReverseLayout() {
- composeList(firstItem = 2, reverseLayout = true)
+ composeGrid(firstItem = 2, reverseLayout = true)
rule.runOnIdle {
runBlocking {
@@ -253,7 +254,7 @@
@Test
fun prefetchingForwardAndBackwardWithContentPadding() {
val halfItemSize = itemsSizeDp / 2f
- composeList(
+ composeGrid(
firstItem = 4,
itemOffset = 5,
contentPadding = PaddingValues(mainAxis = halfItemSize)
@@ -383,6 +384,40 @@
}
}
+ @Test
+ fun scrollingByListSizeCancelsPreviousPrefetch() {
+ composeGrid()
+
+ // now we have items 0-3 visible
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ // this will move the viewport so items 2-5 are visible
+ // and schedule a prefetching for 6-7
+ state.scrollBy(itemsSizePx.toFloat())
+
+ // move viewport by screen size to items 8-11, so item 6 is just behind
+ // the first visible item
+ state.scrollBy(itemsSizePx * 3f)
+
+ // move scroll further to items 10-13, so item 6 is reused
+ state.scrollBy(itemsSizePx.toFloat())
+ }
+ }
+
+ waitForPrefetch(13)
+
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ // scroll again to ensure item 6 was dropped
+ state.scrollBy(itemsSizePx * 100f)
+ }
+ }
+
+ rule.runOnIdle {
+ assertThat(activeNodes).doesNotContain(6)
+ }
+ }
+
private fun waitForPrefetch(index: Int) {
rule.waitUntil {
activeNodes.contains(index) && activeMeasuredNodes.contains(index)
@@ -392,7 +427,7 @@
private val activeNodes = mutableSetOf<Int>()
private val activeMeasuredNodes = mutableSetOf<Int>()
- private fun composeList(
+ private fun composeGrid(
firstItem: Int = 0,
itemOffset: Int = 0,
reverseLayout: Boolean = false,
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListPrefetcherTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListPrefetcherTest.kt
index 59e1c8c..7e40b9b 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListPrefetcherTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListPrefetcherTest.kt
@@ -417,6 +417,40 @@
}
}
+ @Test
+ fun scrollingByListSizeCancelsPreviousPrefetch() {
+ composeList()
+
+ // now we have items 0-1 visible
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ // this will move the viewport so items 1-2 are visible
+ // and schedule a prefetching for 3
+ state.scrollBy(itemsSizePx.toFloat())
+
+ // move viewport by screen size to items 4-5, so item 3 is just behind
+ // the first visible item
+ state.scrollBy(itemsSizePx * 3f)
+
+ // move scroll further to items 5-6, so item 3 is reused
+ state.scrollBy(itemsSizePx.toFloat())
+ }
+ }
+
+ waitForPrefetch(7)
+
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ // scroll again to ensure item 3 was dropped
+ state.scrollBy(itemsSizePx * 100f)
+ }
+ }
+
+ rule.runOnIdle {
+ assertThat(activeNodes).doesNotContain(3)
+ }
+ }
+
private fun waitForPrefetch(index: Int) {
rule.waitUntil {
activeNodes.contains(index) && activeMeasuredNodes.contains(index)
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridPrefetcherTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridPrefetcherTest.kt
index 7747c93..ddaa888 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridPrefetcherTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridPrefetcherTest.kt
@@ -35,6 +35,7 @@
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.unit.Dp
import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
@@ -371,44 +372,154 @@
rule.runOnIdle { }
}
-// @Test
-// fun snappingToOtherPositionWhilePrefetchIsScheduled() {
-// val composedItems = mutableListOf<Int>()
-// rule.setContent {
-// state = rememberLazyGridState()
-// LazyGrid(
-// 1,
-// Modifier.mainAxisSize(itemsSizeDp * 1.5f),
-// state,
-// ) {
-// items(1000) {
-// composedItems.add(it)
-// Spacer(Modifier.mainAxisSize(itemsSizeDp))
-// }
-// }
-// }
-//
-// rule.runOnIdle {
-// // now we have items 0 and 1 visible
-// runBlocking(AutoTestFrameClock()) {
-// // this will move the viewport so items 1 and 2 are visible
-// // and schedule a prefetching for 3
-// state.scrollBy(itemsSizePx.toFloat())
-// // then we move so that items 100 and 101 are visible.
-// // this should cancel the prefetch for 3
-// state.scrollToItem(100)
-// }
-// }
-//
-// // wait a few frames to make sure prefetch happens if was scheduled
-// rule.waitForIdle()
-// rule.waitForIdle()
-// rule.waitForIdle()
-//
-// rule.runOnIdle {
-// Truth.assertThat(composedItems).doesNotContain(3)
-// }
-// }
+ @Test
+ fun snappingToOtherPositionWhilePrefetchIsScheduled() {
+ val composedItems = mutableListOf<Int>()
+ rule.setContent {
+ state = rememberLazyStaggeredGridState()
+ LazyStaggeredGrid(
+ 1,
+ Modifier.mainAxisSize(itemsSizeDp * 1.5f),
+ state,
+ ) {
+ items(1000) {
+ composedItems.add(it)
+ Spacer(Modifier.mainAxisSize(itemsSizeDp))
+ }
+ }
+ }
+
+ rule.runOnIdle {
+ // now we have items 0 and 1 visible
+ runBlocking(AutoTestFrameClock()) {
+ // this will move the viewport so items 1 and 2 are visible
+ // and schedule a prefetching for 3
+ state.scrollBy(itemsSizePx.toFloat())
+ // then we move so that items 100 and 101 are visible.
+ // this should cancel the prefetch for 3
+ state.scrollToItem(100)
+ }
+ }
+
+ // wait a few frames to make sure prefetch happens if was scheduled
+ rule.waitForIdle()
+ rule.waitForIdle()
+ rule.waitForIdle()
+
+ rule.runOnIdle {
+ assertThat(composedItems).doesNotContain(3)
+ }
+ }
+
+ @Test
+ fun scrollingByListSizeCancelsPreviousPrefetch() {
+ composeStaggeredGrid()
+
+ // now we have items 0-3 visible
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ // this will move the viewport so items 2-5 are visible
+ // and schedule a prefetching for 6-7
+ state.scrollBy(itemsSizePx.toFloat())
+
+ // move viewport by screen size to items 8-11, so item 6 is just behind
+ // the first visible item
+ state.scrollBy(itemsSizePx * 3f)
+
+ // move scroll further to items 10-13, so item 6 is reused
+ state.scrollBy(itemsSizePx.toFloat())
+ }
+ }
+
+ waitForPrefetch(13)
+
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ // scroll again to ensure item 6 was dropped
+ state.scrollBy(itemsSizePx * 100f)
+ }
+ }
+
+ rule.runOnIdle {
+ assertThat(activeNodes).doesNotContain(6)
+ }
+ }
+
+ @Test
+ fun scrollingWithStaggeredItemsPrefetchesCorrectly() {
+ rule.setContent {
+ state = rememberLazyStaggeredGridState()
+ LazyStaggeredGrid(
+ 2,
+ Modifier.mainAxisSize(itemsSizeDp * 5f),
+ state,
+ ) {
+ items(100) {
+ DisposableEffect(it) {
+ activeNodes.add(it)
+ onDispose {
+ activeNodes.remove(it)
+ activeMeasuredNodes.remove(it)
+ }
+ }
+ Spacer(
+ Modifier
+ .mainAxisSize(if (it == 0) itemsSizeDp else itemsSizeDp * 2)
+ .border(Dp.Hairline, Color.Black)
+ .testTag("$it")
+ .layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ activeMeasuredNodes.add(it)
+ layout(placeable.width, placeable.height) {
+ placeable.place(0, 0)
+ }
+ }
+ )
+ }
+ }
+ }
+
+ // ┌─┬─┐
+ // ├─┤1│
+ // │2├─┤
+ // ├─┤3│
+ // │4├─┤
+ // └─┴─┘
+
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ // this will move the viewport so item 6 is visible
+ state.scrollBy(itemsSizePx.toFloat())
+ }
+ }
+
+ waitForPrefetch(7)
+ waitForPrefetch(8)
+
+ // ┌─┬─┐
+ // │2├─┤
+ // ├─┤3│
+ // │4├─┤
+ // ├─┤5│
+ // └─┴─┘
+
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ // this will move the viewport so item 7 is visible
+ state.scrollBy(itemsSizePx.toFloat())
+ }
+ assertThat(activeNodes).contains(8)
+ }
+
+ // ┌─┬─┐
+ // ├─┤3│
+ // │4├─┤
+ // ├─┤5│
+ // │6├─┤
+ // └─┴─┘
+
+ waitForPrefetch(9)
+ }
private fun waitForPrefetch(index: Int) {
rule.waitUntil {
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 0d23f23..ffb504c 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
@@ -341,8 +341,12 @@
private fun cancelPrefetchIfVisibleItemsChanged(info: LazyListLayoutInfo) {
if (indexToPrefetch != -1 && info.visibleItemsInfo.isNotEmpty()) {
- if (indexToPrefetch != info.visibleItemsInfo.first().index - 1 &&
- indexToPrefetch != info.visibleItemsInfo.last().index + 1) {
+ val expectedPrefetchIndex = if (wasScrollingForward) {
+ info.visibleItemsInfo.last().index + 1
+ } else {
+ info.visibleItemsInfo.first().index - 1
+ }
+ if (indexToPrefetch != expectedPrefetchIndex) {
indexToPrefetch = -1
currentPrefetchHandle?.cancel()
currentPrefetchHandle = null
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 3f8fdca..428f04e 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
@@ -359,13 +359,16 @@
private fun cancelPrefetchIfVisibleItemsChanged(info: LazyGridLayoutInfo) {
if (lineToPrefetch != -1 && info.visibleItemsInfo.isNotEmpty()) {
- val firstLine = info.visibleItemsInfo.first().let {
- if (isVertical) it.row else it.column
+ val expectedLineToPrefetch = if (wasScrollingForward) {
+ info.visibleItemsInfo.last().let {
+ if (isVertical) it.row else it.column
+ } + 1
+ } else {
+ info.visibleItemsInfo.first().let {
+ if (isVertical) it.row else it.column
+ } - 1
}
- val lastLine = info.visibleItemsInfo.last().let {
- if (isVertical) it.row else it.column
- }
- if (lineToPrefetch != firstLine - 1 && lineToPrefetch != lastLine + 1) {
+ if (lineToPrefetch != expectedLineToPrefetch) {
lineToPrefetch = -1
currentLinePrefetchHandles.forEach { it.cancel() }
currentLinePrefetchHandles.clear()
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 90db4a2..d285d87 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
@@ -29,7 +29,6 @@
import androidx.compose.foundation.lazy.layout.animateScrollToItem
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
-import androidx.compose.runtime.collection.mutableVectorOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.saveable.rememberSaveable
@@ -158,11 +157,10 @@
internal var measurePassCount = 0
/** states required for prefetching **/
- private var wasScrollingForward = true
internal var isVertical = false
internal var laneWidthsPrefixSum: IntArray = IntArray(0)
private var prefetchBaseIndex: Int = -1
- private val currentItemPrefetchHandles = mutableVectorOf<PrefetchHandle>()
+ private val currentItemPrefetchHandles = mutableMapOf<Int, PrefetchHandle>()
/** state required for implementing [animateScrollScope] **/
internal var density: Density = Density(1f, 1f)
@@ -296,15 +294,6 @@
if (info.visibleItemsInfo.isNotEmpty()) {
val scrollingForward = delta < 0
- if (wasScrollingForward != scrollingForward) {
- // the scrolling direction has been changed which means the last prefetched item
- // is not going to be reached anytime soon so it is safer to dispose it.
- // if this item is already visible it is safe to call the method anyway
- // as it will be a no-op
- currentItemPrefetchHandles.forEach { it.cancel() }
- }
-
- wasScrollingForward = scrollingForward
val prefetchIndex = if (scrollingForward) {
info.visibleItemsInfo.last().index
} else {
@@ -316,8 +305,8 @@
return
}
prefetchBaseIndex = prefetchIndex
- currentItemPrefetchHandles.clear()
+ val prefetchHandlesUsed = mutableSetOf<Int>()
var targetIndex = prefetchIndex
for (lane in laneWidthsPrefixSum.indices) {
val previousIndex = targetIndex
@@ -330,11 +319,16 @@
}
if (
targetIndex !in (0 until info.totalItemsCount) ||
- previousIndex == targetIndex
+ previousIndex == targetIndex
) {
return
}
+ prefetchHandlesUsed += targetIndex
+ if (targetIndex in currentItemPrefetchHandles) {
+ continue
+ }
+
val crossAxisSize = laneWidthsPrefixSum[lane] -
if (lane == 0) 0 else laneWidthsPrefixSum[lane - 1]
@@ -344,13 +338,24 @@
Constraints.fixedHeight(crossAxisSize)
}
- currentItemPrefetchHandles.add(
- prefetchState.schedulePrefetch(
- index = targetIndex,
- constraints = constraints
- )
+ currentItemPrefetchHandles[targetIndex] = prefetchState.schedulePrefetch(
+ index = targetIndex,
+ constraints = constraints
)
}
+
+ clearLeftoverPrefetchHandles(prefetchHandlesUsed)
+ }
+ }
+
+ private fun clearLeftoverPrefetchHandles(prefetchHandlesUsed: Set<Int>) {
+ val iterator = currentItemPrefetchHandles.iterator()
+ while (iterator.hasNext()) {
+ val entry = iterator.next()
+ if (entry.key !in prefetchHandlesUsed) {
+ entry.value.cancel()
+ iterator.remove()
+ }
}
}
@@ -359,7 +364,7 @@
if (prefetchBaseIndex != -1 && items.isNotEmpty()) {
if (prefetchBaseIndex !in items.first().index..items.last().index) {
prefetchBaseIndex = -1
- currentItemPrefetchHandles.forEach { it.cancel() }
+ currentItemPrefetchHandles.values.forEach { it.cancel() }
currentItemPrefetchHandles.clear()
}
}
diff --git a/compose/material3/material3/lint-baseline.xml b/compose/material3/material3/lint-baseline.xml
deleted file mode 100644
index 328b7622..0000000
--- a/compose/material3/material3/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?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="IllegalExperimentalApiUsage"
- message="`Experimental` and `RequiresOptIn` APIs may only be used within the same-version group where they were defined."
- errorLine1="@OptIn(ExperimentalTextApi::class)"
- errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/material3/IncludeFontPaddingHelper.android.kt"/>
- </issue>
-
-</issues>
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/font/DeviceFontFamilyNameFontTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/font/DeviceFontFamilyNameFontTest.kt
index 172ced7..716e856 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/font/DeviceFontFamilyNameFontTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/font/DeviceFontFamilyNameFontTest.kt
@@ -33,6 +33,12 @@
val context = InstrumentationRegistry.getInstrumentation().context
+ @Test
+ fun variationSettings_arEmpty() {
+ val font = Font(DeviceFontFamilyName("any name")) as AndroidFont
+ assertThat(font.variationSettings.settings).isEmpty()
+ }
+
@Test(expected = IllegalArgumentException::class)
fun emptyFamilyName_throwsIllegalArgumentException() {
Font(DeviceFontFamilyName(""))
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/HyphensTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/HyphensTest.kt
new file mode 100644
index 0000000..cb93b53
--- /dev/null
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/HyphensTest.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.compose.ui.text.style
+
+import androidx.compose.ui.text.ExperimentalTextApi
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+@OptIn(ExperimentalTextApi::class)
+class HyphensTest : TextLineBreaker() {
+ private val text = "Transformation"
+
+ @Test
+ fun check_hyphens_Auto() {
+ val brokenLines = breakTextIntoLines(
+ text = text,
+ hyphens = Hyphens.Auto,
+ maxWidth = 30
+ )
+ val expected = listOf(
+ "Tran",
+ "sfor",
+ "ma",
+ "tion"
+ )
+ assertThat(brokenLines).isEqualTo(expected)
+ }
+
+ @Test
+ fun check_hyphens_None() {
+ val brokenLines = breakTextIntoLines(
+ text = text,
+ hyphens = Hyphens.None,
+ maxWidth = 30
+ )
+ val expected = listOf(
+ "Tran",
+ "sfor",
+ "mati",
+ "on"
+ )
+ assertThat(brokenLines).isEqualTo(expected)
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/LineBreakTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/LineBreakTest.kt
index e3610d6..69d112c 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/LineBreakTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/LineBreakTest.kt
@@ -16,33 +16,17 @@
package androidx.compose.ui.text.style
-import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.ExperimentalTextApi
-import androidx.compose.ui.text.MultiParagraph
-import androidx.compose.ui.text.TextLayoutInput
-import androidx.compose.ui.text.TextLayoutResult
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.createFontFamilyResolver
-import androidx.compose.ui.unit.Constraints
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.unit.LayoutDirection
-import androidx.compose.ui.unit.constrain
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
import com.google.common.truth.Truth.assertThat
-import kotlin.math.ceil
import org.junit.Test
import org.junit.runner.RunWith
@OptIn(ExperimentalTextApi::class)
@RunWith(AndroidJUnit4::class)
@SmallTest
-class LineBreakTest {
- private val defaultDensity = Density(1f)
- private val context = InstrumentationRegistry.getInstrumentation().context
- private val fontFamilyResolver = createFontFamilyResolver(context)
+class LineBreakTest : TextLineBreaker() {
private val textToLineBreak = "This is an example text"
@Test
@@ -263,63 +247,4 @@
assertThat(brokenLines).isEqualTo(expectedBrokenLines)
}
-
- private fun constructTextLayoutResult(
- text: String,
- textStyle: TextStyle,
- maxWidth: Int = Constraints.Infinity
- ): TextLayoutResult {
- val constraints = Constraints(maxWidth = maxWidth)
-
- val input = TextLayoutInput(
- text = AnnotatedString(text),
- style = textStyle,
- placeholders = listOf(),
- maxLines = Int.MAX_VALUE,
- softWrap = true,
- overflow = TextOverflow.Visible,
- density = defaultDensity,
- layoutDirection = LayoutDirection.Ltr,
- fontFamilyResolver = fontFamilyResolver,
- constraints = constraints
- )
-
- val paragraph = MultiParagraph(
- annotatedString = input.text,
- style = input.style,
- constraints = input.constraints,
- density = input.density,
- fontFamilyResolver = input.fontFamilyResolver
- )
-
- return TextLayoutResult(
- layoutInput = input,
- multiParagraph = paragraph,
- size = constraints.constrain(
- IntSize(
- ceil(paragraph.width).toInt(),
- ceil(paragraph.height).toInt()
- )
- )
- )
- }
-
- private fun breakTextIntoLines(
- text: String,
- lineBreak: LineBreak,
- maxWidth: Int
- ): List<String> {
- val layoutResult = constructTextLayoutResult(
- text = text,
- textStyle = TextStyle(lineBreak = lineBreak),
- maxWidth = maxWidth
- )
-
- return (0 until layoutResult.lineCount).map { lineIndex ->
- text.substring(
- layoutResult.getLineStart(lineIndex),
- layoutResult.getLineEnd(lineIndex)
- )
- }
- }
}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/TextLineBreaker.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/TextLineBreaker.kt
new file mode 100644
index 0000000..6f3ff165
--- /dev/null
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/TextLineBreaker.kt
@@ -0,0 +1,101 @@
+/*
+ * 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.compose.ui.text.style
+
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.MultiParagraph
+import androidx.compose.ui.text.TextLayoutInput
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.createFontFamilyResolver
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.constrain
+import androidx.test.platform.app.InstrumentationRegistry
+import kotlin.math.ceil
+
+@OptIn(ExperimentalTextApi::class)
+open class TextLineBreaker {
+ private val defaultDensity = Density(1f)
+ private val context = InstrumentationRegistry.getInstrumentation().context
+ private val fontFamilyResolver = createFontFamilyResolver(context)
+ private val defaultHyphens = Hyphens.None
+ private val defaultLineBreak = LineBreak.Simple
+
+ private fun constructTextLayoutResult(
+ text: String,
+ textStyle: TextStyle,
+ maxWidth: Int = Constraints.Infinity
+ ): TextLayoutResult {
+ val constraints = Constraints(maxWidth = maxWidth)
+
+ val input = TextLayoutInput(
+ text = AnnotatedString(text),
+ style = textStyle,
+ placeholders = listOf(),
+ maxLines = Int.MAX_VALUE,
+ softWrap = true,
+ overflow = TextOverflow.Visible,
+ density = defaultDensity,
+ layoutDirection = LayoutDirection.Ltr,
+ fontFamilyResolver = fontFamilyResolver,
+ constraints = constraints
+ )
+
+ val paragraph = MultiParagraph(
+ annotatedString = input.text,
+ style = input.style,
+ constraints = input.constraints,
+ density = input.density,
+ fontFamilyResolver = input.fontFamilyResolver
+ )
+
+ return TextLayoutResult(
+ layoutInput = input,
+ multiParagraph = paragraph,
+ size = constraints.constrain(
+ IntSize(
+ ceil(paragraph.width).toInt(),
+ ceil(paragraph.height).toInt()
+ )
+ )
+ )
+ }
+
+ fun breakTextIntoLines(
+ text: String,
+ hyphens: Hyphens = defaultHyphens,
+ lineBreak: LineBreak = defaultLineBreak,
+ maxWidth: Int
+ ): List<String> {
+ val layoutResult = constructTextLayoutResult(
+ text = text,
+ textStyle = TextStyle(hyphens = hyphens, lineBreak = lineBreak),
+ maxWidth = maxWidth
+ )
+
+ return (0 until layoutResult.lineCount).map { lineIndex ->
+ text.substring(
+ layoutResult.getLineStart(lineIndex),
+ layoutResult.getLineEnd(lineIndex)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/font/DeviceFontFamilyNameFont.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/font/DeviceFontFamilyNameFont.kt
index f80d7e2..b9459b5 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/font/DeviceFontFamilyNameFont.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/font/DeviceFontFamilyNameFont.kt
@@ -41,9 +41,15 @@
* This Font can not describe the system-installed [Typeface.DEFAULT]. All other system-installed
* fonts are allowed.
*
+ * Note: When setting [variationSettings] any unset axis may be reset to the font default, ignoring
+ * any axis restrictions in `fonts.xml` or `font_customizations.xml`. This may have surprising
+ * side-effects when named fonts differ only by the default axis settings in XML. When setting
+ * variation axis for device fonts, ensure you set all possible settings for the font.
+ *
* @param familyName Android system-installed font family name
* @param weight weight to load
* @param style style to load
+ * @param variationSettings font variation settings, unset by default to load default VF from system
*
* @throws IllegalArgumentException if familyName is empty
*/
@@ -52,7 +58,7 @@
familyName: DeviceFontFamilyName,
weight: FontWeight = FontWeight.Normal,
style: FontStyle = FontStyle.Normal,
- variationSettings: FontVariation.Settings = FontVariation.Settings(weight, style)
+ variationSettings: FontVariation.Settings = FontVariation.Settings()
): Font {
return DeviceFontFamilyNameFont(familyName, weight, style, variationSettings)
}
@@ -60,6 +66,8 @@
/**
* An Android system installed font family name as used by [Typeface.create].
*
+ * See `/system/etc/fonts.xml` and `/product/etc/fonts_customization.xml` on a device.
+ *
* @see Typeface
* @param name System fontFamilyName as passed to [Typeface.create]
* @throws IllegalArgumentException if name is empty
diff --git a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/recyclerview/RecyclerViewInteropDemoFragment.kt b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/recyclerview/RecyclerViewInteropDemoFragment.kt
index 08b683d..507e519 100644
--- a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/recyclerview/RecyclerViewInteropDemoFragment.kt
+++ b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/recyclerview/RecyclerViewInteropDemoFragment.kt
@@ -28,12 +28,12 @@
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
@@ -66,6 +66,8 @@
}
inner class MainAdapter : RecyclerView.Adapter<MainAdapter.ViewHolder>() {
+ private val rowStates = mutableMapOf<Int, LazyListState>()
+
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val itemRow: ComposeItemRow = itemView.findViewById(R.id.itemRow)
}
@@ -76,7 +78,9 @@
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val state = rowStates.getOrPut(position) { LazyListState() }
holder.itemRow.index = position
+ holder.itemRow.rowState = state
}
override fun getItemCount(): Int = 50
@@ -84,7 +88,7 @@
}
@Composable
-fun ItemRow(index: Int) {
+fun ItemRow(index: Int, state: LazyListState) {
DisposableEffect(Unit) {
println("ItemRow $index composed")
@@ -92,12 +96,14 @@
}
Column(Modifier.fillMaxWidth()) {
Text("Row #${index + 1}", Modifier.padding(horizontal = 8.dp))
- LazyRow {
+
+ LazyRow(state = state) {
items(25) { colIdx ->
Column(
Modifier
.padding(8.dp)
- .size(96.dp, 144.dp)) {
+ .size(96.dp, 144.dp)
+ ) {
Box(
Modifier
.fillMaxWidth()
@@ -117,11 +123,10 @@
defStyle: Int = 0
) : AbstractComposeView(context, attrs, defStyle) {
var index by mutableStateOf(0)
+ var rowState: LazyListState? by mutableStateOf(null)
@Composable
override fun Content() {
- key(index) {
- ItemRow(index)
- }
+ ItemRow(index, rowState!!)
}
}
diff --git a/contentpager/contentpager/lint-baseline.xml b/contentpager/contentpager/lint-baseline.xml
index 87af2b4..de601d0 100644
--- a/contentpager/contentpager/lint-baseline.xml
+++ b/contentpager/contentpager/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
<issue
id="NewApi"
diff --git a/core/core-appdigest/lint-baseline.xml b/core/core-appdigest/lint-baseline.xml
index f90928c..0907387 100644
--- a/core/core-appdigest/lint-baseline.xml
+++ b/core/core-appdigest/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<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="NewApi"
diff --git a/core/core/lint-baseline.xml b/core/core/lint-baseline.xml
index c7ef3b1..7762518 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 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<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="NewApi"
@@ -697,33 +697,6 @@
<issue
id="WrongConstant"
message="Must be one of: Action.SEMANTIC_ACTION_NONE, Action.SEMANTIC_ACTION_REPLY, Action.SEMANTIC_ACTION_MARK_AS_READ, Action.SEMANTIC_ACTION_MARK_AS_UNREAD, Action.SEMANTIC_ACTION_DELETE, Action.SEMANTIC_ACTION_ARCHIVE, Action.SEMANTIC_ACTION_MUTE, Action.SEMANTIC_ACTION_UNMUTE, Action.SEMANTIC_ACTION_THUMBS_UP, Action.SEMANTIC_ACTION_THUMBS_DOWN, Action.SEMANTIC_ACTION_CALL"
- errorLine1=" builder.setSemanticAction(action.getSemanticAction());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="WrongConstant"
- message="Must be one of: RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO, RemoteInput.EDIT_CHOICES_BEFORE_SENDING_DISABLED, RemoteInput.EDIT_CHOICES_BEFORE_SENDING_ENABLED"
- errorLine1=" ? remoteInput.getEditChoicesBeforeSending()"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="WrongConstant"
- message="Must be one of: RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO, RemoteInput.EDIT_CHOICES_BEFORE_SENDING_DISABLED, RemoteInput.EDIT_CHOICES_BEFORE_SENDING_ENABLED"
- errorLine1=" ? src.getEditChoicesBeforeSending()"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="WrongConstant"
- message="Must be one of: Action.SEMANTIC_ACTION_NONE, Action.SEMANTIC_ACTION_REPLY, Action.SEMANTIC_ACTION_MARK_AS_READ, Action.SEMANTIC_ACTION_MARK_AS_UNREAD, Action.SEMANTIC_ACTION_DELETE, Action.SEMANTIC_ACTION_ARCHIVE, Action.SEMANTIC_ACTION_MUTE, Action.SEMANTIC_ACTION_UNMUTE, Action.SEMANTIC_ACTION_THUMBS_UP, Action.SEMANTIC_ACTION_THUMBS_DOWN, Action.SEMANTIC_ACTION_CALL"
errorLine1=" actionBuilder.setSemanticAction(action.getSemanticAction());"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
@@ -2181,927 +2154,9 @@
<issue
id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" this(channel.getId(), channel.getImportance());"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" this(channel.getId(), channel.getImportance());"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mName = channel.getName();"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mDescription = channel.getDescription();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mGroupId = channel.getGroup();"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mShowBadge = channel.canShowBadge();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mSound = channel.getSound();"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mAudioAttributes = channel.getAudioAttributes();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mLights = channel.shouldShowLights();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mLightColor = channel.getLightColor();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mVibrationEnabled = channel.shouldVibrate();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mVibrationPattern = channel.getVibrationPattern();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mParentId = channel.getParentChannelId();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mConversationId = channel.getConversationId();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBypassDnd = channel.canBypassDnd();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mLockscreenVisibility = channel.getLockscreenVisibility();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mCanBubble = channel.canBubble();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mImportantConversation = channel.isImportantConversation();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" NotificationChannel channel = new NotificationChannel(mId, mName, mImportance);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" channel.setDescription(mDescription);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" channel.setGroup(mGroupId);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" channel.setShowBadge(mShowBadge);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" channel.setSound(mSound, mAudioAttributes);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" channel.enableLights(mLights);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" channel.setLightColor(mLightColor);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" channel.setVibrationPattern(mVibrationPattern);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" channel.enableVibration(mVibrationEnabled);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.app.NotificationChannelCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" channel.setConversationId(mParentId, mConversationId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelGroupCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" this(group.getId());"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelGroupCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelGroupCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mName = group.getName();"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelGroupCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.NotificationChannelGroupCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mDescription = group.getDescription();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelGroupCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.NotificationChannelGroupCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mBlocked = group.isBlocked();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelGroupCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelGroupCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mChannels = getChannelsCompat(group.getChannels());"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelGroupCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelGroupCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (mId.equals(channel.getGroup())) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelGroupCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationChannelGroupCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" NotificationChannelGroup group = new NotificationChannelGroup(mId, mName);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelGroupCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.NotificationChannelGroupCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" group.setDescription(mDescription);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationChannelGroupCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" this.mSmallIcon = notification.getSmallIcon();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mNotification.audioAttributes = new AudioAttributes.Builder()"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setUsage(AudioAttributes.USAGE_NOTIFICATION)"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mNotification.audioAttributes = new AudioAttributes.Builder()"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setLegacyStreamType(streamType)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Notification.Builder.recoverBuilder(mContext, notification)"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .createContentView();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Notification.Builder.recoverBuilder(mContext, notification)"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .createBigContentView();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Notification.Builder.recoverBuilder(mContext, notification);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return platformBuilder.createHeadsUpContentView();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.Style is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.Style is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.Style is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" contentView.setChronometerCountDown(R.id.chronometer,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.Style is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" outerView.setViewPadding(R.id.notification_main_column_container,"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.BigPictureStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" new Notification.BigPictureStyle(builder.getBuilder())"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.BigPictureStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setBigContentTitle(mBigContentTitle);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.BigPictureStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" style = style.bigPicture(mPictureIcon.getBitmap());"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.BigTextStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" new Notification.BigTextStyle(builder.getBuilder())"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.BigTextStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setBigContentTitle(mBigContentTitle)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.BigTextStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .bigText(mBigText);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.BigTextStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" style.setSummaryText(mSummaryText);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.NotificationCompat.MessagingStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameworkStyle = new Notification.MessagingStyle(mUser.toAndroidPerson());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.MessagingStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameworkStyle = new Notification.MessagingStyle(mUser.getName());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.MessagingStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameworkStyle.addMessage(message.toAndroidMessage());"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationCompat.MessagingStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameworkStyle.addHistoricMessage(historicMessage.toAndroidMessage());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.MessagingStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameworkStyle.setConversationTitle(mConversationTitle);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.NotificationCompat.MessagingStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameworkStyle.setGroupConversation(mIsGroupConversation);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.MessagingStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameworkStyle.setBuilder(builder.getBuilder());"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.MessagingStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" new Notification.BigTextStyle(builder.getBuilder())"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.MessagingStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setBigContentTitle(null)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.MessagingStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .bigText(completeMessage);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.NotificationCompat.MessagingStyle.Message is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameworkMessage = new Notification.MessagingStyle.Message("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.MessagingStyle.Message is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameworkMessage = new Notification.MessagingStyle.Message("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.MessagingStyle.Message is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" frameworkMessage.setData(getDataMimeType(), getDataUri());"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.InboxStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" new Notification.InboxStyle(builder.getBuilder())"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.InboxStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .setBigContentTitle(mBigContentTitle);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.InboxStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" style.setSummaryText(mSummaryText);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.InboxStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" style.addLine(text);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 16; however, the containing class androidx.core.app.NotificationCompat.DecoratedCustomViewStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.getBuilder().setStyle(new Notification.DecoratedCustomViewStyle());"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.DecoratedCustomViewStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.getBuilder().setStyle(new Notification.DecoratedCustomViewStyle());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 15; however, the containing class androidx.core.app.NotificationCompat.DecoratedCustomViewStyle is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" button.setContentDescription(R.id.action_container, action.title);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.NotificationCompat.Action.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (Build.VERSION.SDK_INT >= 23 && action.getIcon() != null) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.NotificationCompat.Action.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" IconCompat iconCompat = IconCompat.createFromIcon(action.getIcon());"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat.Action.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" android.app.RemoteInput[] remoteInputs = action.getRemoteInputs();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.Action.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.mAllowGeneratedReplies = action.getAllowGeneratedReplies();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.NotificationCompat.Action.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setSemanticAction(action.getSemanticAction());"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.NotificationCompat.Action.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setContextual(action.isContextual());"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 31; however, the containing class androidx.core.app.NotificationCompat.Action.Builder is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" builder.setAuthenticationRequired(action.isAuthenticationRequired());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.NotificationCompat.WearableExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" actionBuilder = new Notification.Action.Builder("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat.WearableExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" actionBuilder = new Notification.Action.Builder("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat.WearableExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" actionBuilder.setAllowGeneratedReplies(actionCompat.getAllowGeneratedReplies());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 31; however, the containing class androidx.core.app.NotificationCompat.WearableExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" actionBuilder.setAuthenticationRequired(actionCompat.isAuthenticationRequired());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat.WearableExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" actionBuilder.addExtras(actionExtras);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat.WearableExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" actionBuilder.addRemoteInput(remoteInput);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat.WearableExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return actionBuilder.build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat.CarExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ? new RemoteInput(remoteInput.getResultKey(),"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat.CarExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" remoteInput.getLabel(),"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat.CarExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" remoteInput.getChoices(),"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat.CarExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" remoteInput.getAllowFreeFormInput(),"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.NotificationCompat.CarExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ? remoteInput.getEditChoicesBeforeSending()"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat.CarExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" remoteInput.getExtras(),"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat.CarExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" new android.app.RemoteInput.Builder(remoteInputCompat.getResultKey())"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ errorLine1=" Api20Impl.build(new android.app.RemoteInput.Builder("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"/>
</issue>
@@ -3136,7 +2191,7 @@
<issue
id="ClassVerificationFailure"
message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat.CarExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .addExtras(remoteInputCompat.getExtras())"
+ errorLine1=" .addExtras(remoteInputCompat.getExtras()));"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/androidx/core/app/NotificationCompat.java"/>
@@ -3144,303 +2199,6 @@
<issue
id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat.CarExtender is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" .build();"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return BubbleMetadata.fromPlatform(notification.getBubbleMetadata());"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" final android.app.RemoteInput[] srcArray = action.getRemoteInputs();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" src.getResultKey(),"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" src.getLabel(),"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" src.getChoices(),"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" src.getAllowFreeFormInput(),"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ? src.getEditChoicesBeforeSending()"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" src.getExtras(),"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" allowGeneratedReplies = action.getExtras().getBoolean("
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" || action.getAllowGeneratedReplies();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" allowGeneratedReplies = action.getExtras().getBoolean("
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" action.getExtras().getBoolean(Action.EXTRA_SHOWS_USER_INTERFACE, true);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" semanticAction = action.getSemanticAction();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" semanticAction = action.getExtras().getInt("
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" final boolean isContextual = Build.VERSION.SDK_INT >= 29 ? action.isContextual() : false;"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 31; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Build.VERSION.SDK_INT >= 31 ? action.isAuthenticationRequired() : false;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (action.getIcon() == null && action.icon != 0) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" action.getExtras(), remoteInputs, null, allowGeneratedReplies,"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" IconCompat icon = action.getIcon() == null"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" ? null : IconCompat.createFromIconOrNullIfZeroResId(action.getIcon());"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new Action(icon, action.title, action.actionIntent, action.getExtras(),"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new Action(action.icon, action.title, action.actionIntent, action.getExtras(),"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return notification.getGroup();"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 20; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return notification.getSortKey();"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return notification.getChannelId();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return notification.getTimeoutAfter();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return notification.getBadgeIconType();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return notification.getShortcutId();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return notification.getSettingsText();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" LocusId locusId = notification.getLocusId();"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return notification.getGroupAlertBehavior();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.core.app.NotificationCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return notification.getAllowSystemGeneratedContextualActions();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationCompatBuilder is reachable from earlier API levels and will fail run-time class verification."
errorLine1=" mBuilder = new Notification.Builder(b.mContext, b.mChannelId);"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -3972,195 +2730,6 @@
<issue
id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mNotificationManager.areNotificationsEnabled();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 24; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mNotificationManager.getImportance();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mNotificationManager.createNotificationChannel(channel);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mNotificationManager.createNotificationChannelGroup(group);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mNotificationManager.createNotificationChannels(channels);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mNotificationManager.createNotificationChannels(platformChannels);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mNotificationManager.createNotificationChannelGroups(groups);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mNotificationManager.createNotificationChannelGroups(platformGroups);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mNotificationManager.deleteNotificationChannel(channelId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mNotificationManager.deleteNotificationChannelGroup(groupId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" for (NotificationChannel channel : mNotificationManager.getNotificationChannels()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (channelIds.contains(channel.getId())) {"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" && channelIds.contains(channel.getParentChannelId())) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mNotificationManager.deleteNotificationChannel(channel.getId());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mNotificationManager.deleteNotificationChannel(channel.getId());"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mNotificationManager.getNotificationChannel(channelId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 30; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mNotificationManager.getNotificationChannel(channelId, conversationId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mNotificationManager.getNotificationChannelGroup(channelGroupId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" if (group.getId().equals(channelGroupId)) return group;"
- errorLine2=" ~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mNotificationManager.getNotificationChannels();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.core.app.NotificationManagerCompat is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return mNotificationManager.getNotificationChannelGroups();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/NotificationManagerCompat.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
message="This call references a method added in API level 28; however, the containing class androidx.core.text.PrecomputedTextCompat.Params is reachable from earlier API levels and will fail run-time class verification."
errorLine1=" mWrapped = new PrecomputedText.Params.Builder(paint)"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
diff --git a/credentials/credentials-play-services-auth/build.gradle b/credentials/credentials-play-services-auth/build.gradle
index 2125f1d..bf17414 100644
--- a/credentials/credentials-play-services-auth/build.gradle
+++ b/credentials/credentials-play-services-auth/build.gradle
@@ -29,6 +29,10 @@
android {
namespace "androidx.credentials.play.services.auth"
+
+ defaultConfig {
+ minSdkVersion 19
+ }
}
androidx {
diff --git a/credentials/credentials-provider/api/current.txt b/credentials/credentials-provider/api/current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/credentials/credentials-provider/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/credentials/credentials-provider/api/public_plus_experimental_current.txt b/credentials/credentials-provider/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/credentials/credentials-provider/api/public_plus_experimental_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/credentials/credentials-provider/api/res-current.txt b/credentials/credentials-provider/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/credentials/credentials-provider/api/res-current.txt
diff --git a/credentials/credentials-provider/api/restricted_current.txt b/credentials/credentials-provider/api/restricted_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/credentials/credentials-provider/api/restricted_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/credentials/credentials-provider/build.gradle b/credentials/credentials-provider/build.gradle
new file mode 100644
index 0000000..f56c18c
--- /dev/null
+++ b/credentials/credentials-provider/build.gradle
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 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 androidx.build.LibraryType
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+ api(libs.kotlinStdlib)
+ // Add dependencies here
+}
+
+android {
+ namespace "androidx.credentials.provider"
+
+ defaultConfig {
+ minSdkVersion 19
+ }
+}
+
+androidx {
+ name = "Credentials Provider Library"
+ type = LibraryType.PUBLISHED_LIBRARY
+ mavenGroup = LibraryGroups.CREDENTIALS
+ inceptionYear = "2022"
+ description = "use utility APIs to process requests from, and return responses to the android" +
+ "Credential Manager"
+}
diff --git a/credentials/credentials-provider/src/main/androidx/credentials/androidx-credentials-credentials-provider-documentation.md b/credentials/credentials-provider/src/main/androidx/credentials/androidx-credentials-credentials-provider-documentation.md
new file mode 100644
index 0000000..d3a5d02
--- /dev/null
+++ b/credentials/credentials-provider/src/main/androidx/credentials/androidx-credentials-credentials-provider-documentation.md
@@ -0,0 +1,8 @@
+# Module root
+
+CREDENTIALS CREDENTIALS PROVIDER
+
+# Package androidx.credentials.provider
+
+This package provides utility APIs for providers to use as they respond to credential requests
+from the android Credential Manager.
\ No newline at end of file
diff --git a/credentials/credentials/api/current.txt b/credentials/credentials/api/current.txt
index e6f50d0..014f0be 100644
--- a/credentials/credentials/api/current.txt
+++ b/credentials/credentials/api/current.txt
@@ -1 +1,75 @@
// Signature format: 4.0
+package androidx.credentials {
+
+ public abstract class CreateCredentialRequest {
+ ctor public CreateCredentialRequest();
+ }
+
+ public abstract class CreateCredentialResponse {
+ ctor public CreateCredentialResponse();
+ }
+
+ public final class CreatePasswordRequest extends androidx.credentials.CreateCredentialRequest {
+ ctor public CreatePasswordRequest(String id, String password);
+ method public String getId();
+ method public String getPassword();
+ property public final String id;
+ property public final String password;
+ }
+
+ public final class CreatePasswordResponse extends androidx.credentials.CreateCredentialResponse {
+ ctor public CreatePasswordResponse();
+ }
+
+ public abstract class Credential {
+ ctor public Credential();
+ }
+
+ public final class CredentialManager {
+ method public static androidx.credentials.CredentialManager create(android.content.Context context);
+ method public suspend Object? executeCreateCredential(androidx.credentials.CreateCredentialRequest request, kotlin.coroutines.Continuation<? super androidx.credentials.CreateCredentialResponse>);
+ method public suspend Object? executeGetCredential(androidx.credentials.GetCredentialRequest request, kotlin.coroutines.Continuation<? super androidx.credentials.GetCredentialResponse>);
+ field public static final androidx.credentials.CredentialManager.Companion Companion;
+ }
+
+ public static final class CredentialManager.Companion {
+ method public androidx.credentials.CredentialManager create(android.content.Context context);
+ }
+
+ public abstract class GetCredentialOption {
+ ctor public GetCredentialOption();
+ }
+
+ public final class GetCredentialRequest {
+ ctor public GetCredentialRequest(java.util.List<? extends androidx.credentials.GetCredentialOption> getCredentialOptions);
+ method public java.util.List<androidx.credentials.GetCredentialOption> getGetCredentialOptions();
+ property public final java.util.List<androidx.credentials.GetCredentialOption> getCredentialOptions;
+ }
+
+ public static final class GetCredentialRequest.Builder {
+ ctor public GetCredentialRequest.Builder();
+ method public androidx.credentials.GetCredentialRequest.Builder addGetCredentialOption(androidx.credentials.GetCredentialOption getCredentialOption);
+ method public androidx.credentials.GetCredentialRequest build();
+ method public androidx.credentials.GetCredentialRequest.Builder setGetCredentialOptions(java.util.List<? extends androidx.credentials.GetCredentialOption> getCredentialOptions);
+ }
+
+ public final class GetCredentialResponse {
+ ctor public GetCredentialResponse(androidx.credentials.Credential credential);
+ method public androidx.credentials.Credential getCredential();
+ property public final androidx.credentials.Credential credential;
+ }
+
+ public final class GetPasswordOption extends androidx.credentials.GetCredentialOption {
+ ctor public GetPasswordOption();
+ }
+
+ public final class PasswordCredential extends androidx.credentials.Credential {
+ ctor public PasswordCredential(String id, String password);
+ method public String getId();
+ method public String getPassword();
+ property public final String id;
+ property public final String password;
+ }
+
+}
+
diff --git a/credentials/credentials/api/public_plus_experimental_current.txt b/credentials/credentials/api/public_plus_experimental_current.txt
index e6f50d0..014f0be 100644
--- a/credentials/credentials/api/public_plus_experimental_current.txt
+++ b/credentials/credentials/api/public_plus_experimental_current.txt
@@ -1 +1,75 @@
// Signature format: 4.0
+package androidx.credentials {
+
+ public abstract class CreateCredentialRequest {
+ ctor public CreateCredentialRequest();
+ }
+
+ public abstract class CreateCredentialResponse {
+ ctor public CreateCredentialResponse();
+ }
+
+ public final class CreatePasswordRequest extends androidx.credentials.CreateCredentialRequest {
+ ctor public CreatePasswordRequest(String id, String password);
+ method public String getId();
+ method public String getPassword();
+ property public final String id;
+ property public final String password;
+ }
+
+ public final class CreatePasswordResponse extends androidx.credentials.CreateCredentialResponse {
+ ctor public CreatePasswordResponse();
+ }
+
+ public abstract class Credential {
+ ctor public Credential();
+ }
+
+ public final class CredentialManager {
+ method public static androidx.credentials.CredentialManager create(android.content.Context context);
+ method public suspend Object? executeCreateCredential(androidx.credentials.CreateCredentialRequest request, kotlin.coroutines.Continuation<? super androidx.credentials.CreateCredentialResponse>);
+ method public suspend Object? executeGetCredential(androidx.credentials.GetCredentialRequest request, kotlin.coroutines.Continuation<? super androidx.credentials.GetCredentialResponse>);
+ field public static final androidx.credentials.CredentialManager.Companion Companion;
+ }
+
+ public static final class CredentialManager.Companion {
+ method public androidx.credentials.CredentialManager create(android.content.Context context);
+ }
+
+ public abstract class GetCredentialOption {
+ ctor public GetCredentialOption();
+ }
+
+ public final class GetCredentialRequest {
+ ctor public GetCredentialRequest(java.util.List<? extends androidx.credentials.GetCredentialOption> getCredentialOptions);
+ method public java.util.List<androidx.credentials.GetCredentialOption> getGetCredentialOptions();
+ property public final java.util.List<androidx.credentials.GetCredentialOption> getCredentialOptions;
+ }
+
+ public static final class GetCredentialRequest.Builder {
+ ctor public GetCredentialRequest.Builder();
+ method public androidx.credentials.GetCredentialRequest.Builder addGetCredentialOption(androidx.credentials.GetCredentialOption getCredentialOption);
+ method public androidx.credentials.GetCredentialRequest build();
+ method public androidx.credentials.GetCredentialRequest.Builder setGetCredentialOptions(java.util.List<? extends androidx.credentials.GetCredentialOption> getCredentialOptions);
+ }
+
+ public final class GetCredentialResponse {
+ ctor public GetCredentialResponse(androidx.credentials.Credential credential);
+ method public androidx.credentials.Credential getCredential();
+ property public final androidx.credentials.Credential credential;
+ }
+
+ public final class GetPasswordOption extends androidx.credentials.GetCredentialOption {
+ ctor public GetPasswordOption();
+ }
+
+ public final class PasswordCredential extends androidx.credentials.Credential {
+ ctor public PasswordCredential(String id, String password);
+ method public String getId();
+ method public String getPassword();
+ property public final String id;
+ property public final String password;
+ }
+
+}
+
diff --git a/credentials/credentials/api/restricted_current.txt b/credentials/credentials/api/restricted_current.txt
index e6f50d0..014f0be 100644
--- a/credentials/credentials/api/restricted_current.txt
+++ b/credentials/credentials/api/restricted_current.txt
@@ -1 +1,75 @@
// Signature format: 4.0
+package androidx.credentials {
+
+ public abstract class CreateCredentialRequest {
+ ctor public CreateCredentialRequest();
+ }
+
+ public abstract class CreateCredentialResponse {
+ ctor public CreateCredentialResponse();
+ }
+
+ public final class CreatePasswordRequest extends androidx.credentials.CreateCredentialRequest {
+ ctor public CreatePasswordRequest(String id, String password);
+ method public String getId();
+ method public String getPassword();
+ property public final String id;
+ property public final String password;
+ }
+
+ public final class CreatePasswordResponse extends androidx.credentials.CreateCredentialResponse {
+ ctor public CreatePasswordResponse();
+ }
+
+ public abstract class Credential {
+ ctor public Credential();
+ }
+
+ public final class CredentialManager {
+ method public static androidx.credentials.CredentialManager create(android.content.Context context);
+ method public suspend Object? executeCreateCredential(androidx.credentials.CreateCredentialRequest request, kotlin.coroutines.Continuation<? super androidx.credentials.CreateCredentialResponse>);
+ method public suspend Object? executeGetCredential(androidx.credentials.GetCredentialRequest request, kotlin.coroutines.Continuation<? super androidx.credentials.GetCredentialResponse>);
+ field public static final androidx.credentials.CredentialManager.Companion Companion;
+ }
+
+ public static final class CredentialManager.Companion {
+ method public androidx.credentials.CredentialManager create(android.content.Context context);
+ }
+
+ public abstract class GetCredentialOption {
+ ctor public GetCredentialOption();
+ }
+
+ public final class GetCredentialRequest {
+ ctor public GetCredentialRequest(java.util.List<? extends androidx.credentials.GetCredentialOption> getCredentialOptions);
+ method public java.util.List<androidx.credentials.GetCredentialOption> getGetCredentialOptions();
+ property public final java.util.List<androidx.credentials.GetCredentialOption> getCredentialOptions;
+ }
+
+ public static final class GetCredentialRequest.Builder {
+ ctor public GetCredentialRequest.Builder();
+ method public androidx.credentials.GetCredentialRequest.Builder addGetCredentialOption(androidx.credentials.GetCredentialOption getCredentialOption);
+ method public androidx.credentials.GetCredentialRequest build();
+ method public androidx.credentials.GetCredentialRequest.Builder setGetCredentialOptions(java.util.List<? extends androidx.credentials.GetCredentialOption> getCredentialOptions);
+ }
+
+ public final class GetCredentialResponse {
+ ctor public GetCredentialResponse(androidx.credentials.Credential credential);
+ method public androidx.credentials.Credential getCredential();
+ property public final androidx.credentials.Credential credential;
+ }
+
+ public final class GetPasswordOption extends androidx.credentials.GetCredentialOption {
+ ctor public GetPasswordOption();
+ }
+
+ public final class PasswordCredential extends androidx.credentials.Credential {
+ ctor public PasswordCredential(String id, String password);
+ method public String getId();
+ method public String getPassword();
+ property public final String id;
+ property public final String password;
+ }
+
+}
+
diff --git a/credentials/credentials/build.gradle b/credentials/credentials/build.gradle
index 0536e04..e42b992 100644
--- a/credentials/credentials/build.gradle
+++ b/credentials/credentials/build.gradle
@@ -24,11 +24,23 @@
dependencies {
api(libs.kotlinStdlib)
- // Add dependencies here
+
+ androidTestImplementation(libs.junit)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.truth)
+ androidTestImplementation(project(":internal-testutils-truth"))
+ androidTestImplementation(libs.kotlinCoroutinesAndroid)
}
android {
namespace "androidx.credentials"
+
+ defaultConfig {
+ minSdkVersion 19
+ }
}
androidx {
diff --git a/credentials/credentials/src/androidTest/AndroidManifest.xml b/credentials/credentials/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..4995896
--- /dev/null
+++ b/credentials/credentials/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+</manifest>
\ No newline at end of file
diff --git a/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerTest.kt b/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerTest.kt
new file mode 100644
index 0000000..81ec28f
--- /dev/null
+++ b/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerTest.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.credentials
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.testutils.assertThrows
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class CredentialManagerTest {
+ private val context = InstrumentationRegistry.getInstrumentation().context
+
+ private lateinit var credentialManager: CredentialManager
+
+ @Before
+ fun setup() {
+ credentialManager = CredentialManager.create(context)
+ }
+
+ @Test
+ fun testCreateCredential() = runBlocking<Unit> {
+ assertThrows<UnsupportedOperationException> {
+ credentialManager.executeCreateCredential(
+ CreatePasswordRequest("test-user-id", "test-password")
+ )
+ }
+ }
+
+ @Test
+ fun testGetCredential() = runBlocking<Unit> {
+ val request = GetCredentialRequest.Builder()
+ .addGetCredentialOption(GetPasswordOption())
+ .build()
+ assertThrows<UnsupportedOperationException> {
+ credentialManager.executeGetCredential(request)
+ }
+ }
+}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialRequest.kt b/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialRequest.kt
new file mode 100644
index 0000000..d630fa7
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialRequest.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.credentials
+
+/**
+ * Base request class for registering a credential.
+ *
+ * An application can construct a subtype request and call [CredentialManager.executeCreateCredential] to
+ * launch framework UI flows to collect consent and any other metadata needed from the user to
+ * register a new user credential.
+ */
+abstract class CreateCredentialRequest
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialResponse.kt b/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialResponse.kt
new file mode 100644
index 0000000..192d472
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/CreateCredentialResponse.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.credentials
+
+/** Base response class for registering a credential. */
+abstract class CreateCredentialResponse
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordRequest.kt b/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordRequest.kt
new file mode 100644
index 0000000..2fc0116
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordRequest.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.credentials
+
+/**
+ * A request to save the user password credential with their password provider.
+ *
+ * @property id the user id associated with the password
+ * @property password the password
+ * @throws NullPointerException If [id] is null
+ * @throws NullPointerException If [password] is null
+ * @throws IllegalArgumentException If [password] is empty
+ */
+class CreatePasswordRequest constructor(
+ val id: String,
+ val password: String,
+) : CreateCredentialRequest() {
+
+ init {
+ require(password.isNotEmpty()) { "password should not be empty" }
+ }
+}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordResponse.kt b/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordResponse.kt
new file mode 100644
index 0000000..d70468c
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/CreatePasswordResponse.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.credentials
+
+/** A response of a password saving flow. */
+class CreatePasswordResponse : CreateCredentialResponse()
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/Credential.kt b/credentials/credentials/src/main/java/androidx/credentials/Credential.kt
new file mode 100644
index 0000000..eb19ff8
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/Credential.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.credentials
+
+/** Base class for a credential with which the user consented to authenticate to the app. */
+abstract class Credential
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CredentialManager.kt b/credentials/credentials/src/main/java/androidx/credentials/CredentialManager.kt
new file mode 100644
index 0000000..04e27f1c
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/CredentialManager.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.credentials
+
+import android.content.Context
+
+/**
+ * Manages user authentication flows.
+ *
+ * An application can call the CredentialManager apis to launch framework UI flows for a user to
+ * register a new credential or to consent to a saved credential from supported credential
+ * providers, which can then be used to authenticate to the app.
+ */
+@Suppress("UNUSED_PARAMETER")
+class CredentialManager private constructor(private val context: Context) {
+ companion object {
+ @JvmStatic
+ fun create(context: Context): CredentialManager = CredentialManager(context)
+ }
+
+ /**
+ * Requests a credential from the user.
+ *
+ * The execution potentially launches framework UI flows for a user to view available
+ * credentials, consent to using one of them, etc.
+ *
+ * @throws UnsupportedOperationException Since the api is unimplemented
+ */
+ // TODO(helenqin): support failure flow.
+ suspend fun executeGetCredential(request: GetCredentialRequest): GetCredentialResponse {
+ throw UnsupportedOperationException("Unimplemented")
+ }
+
+ /**
+ * Registers a user credential that can be used to authenticate the user to
+ * the app in the future.
+ *
+ * The execution potentially launches framework UI flows for a user to view their registration
+ * options, grant consent, etc.
+ *
+ * @throws UnsupportedOperationException Since the api is unimplemented
+ */
+ suspend fun executeCreateCredential(
+ request: CreateCredentialRequest
+ ): CreateCredentialResponse {
+ throw UnsupportedOperationException("Unimplemented")
+ }
+}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/GetCredentialOption.kt b/credentials/credentials/src/main/java/androidx/credentials/GetCredentialOption.kt
new file mode 100644
index 0000000..2fcd72a
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/GetCredentialOption.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.credentials
+
+/** Base request class for getting a registered credential. */
+abstract class GetCredentialOption
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/GetCredentialRequest.kt b/credentials/credentials/src/main/java/androidx/credentials/GetCredentialRequest.kt
new file mode 100644
index 0000000..165198a
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/GetCredentialRequest.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.credentials
+
+/**
+ * Encapsulates a request to get a user credential.
+ *
+ * An application can construct such a request by adding one or more types of [GetCredentialOption],
+ * and then call [CredentialManager.executeGetCredential] to launch framework UI flows to allow the user
+ * to consent to using a previously saved credential for the given application.
+ *
+ * @property getCredentialOptions the list of [GetCredentialOption] from which the user can choose
+ * one to authenticate to the app
+ * @throws IllegalArgumentException If [getCredentialOptions] is empty
+ */
+class GetCredentialRequest constructor(
+ val getCredentialOptions: List<GetCredentialOption>,
+) {
+
+ init {
+ require(getCredentialOptions.isNotEmpty()) { "credentialRequests should not be empty" }
+ }
+
+ /** A builder for [GetCredentialRequest]. */
+ class Builder {
+ private var getCredentialOptions: MutableList<GetCredentialOption> = mutableListOf()
+
+ /** Adds a specific type of [GetCredentialOption]. */
+ fun addGetCredentialOption(getCredentialOption: GetCredentialOption): Builder {
+ getCredentialOptions.add(getCredentialOption)
+ return this
+ }
+
+ /** Sets the list of [GetCredentialOption]. */
+ fun setGetCredentialOptions(getCredentialOptions: List<GetCredentialOption>): Builder {
+ this.getCredentialOptions = getCredentialOptions.toMutableList()
+ return this
+ }
+
+ /**
+ * Builds a [GetCredentialRequest].
+ *
+ * @throws IllegalArgumentException If [getCredentialOptions] is empty
+ */
+ fun build(): GetCredentialRequest {
+ return GetCredentialRequest(getCredentialOptions.toList())
+ }
+ }
+}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/GetCredentialResponse.kt b/credentials/credentials/src/main/java/androidx/credentials/GetCredentialResponse.kt
new file mode 100644
index 0000000..1a2b624
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/GetCredentialResponse.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.credentials
+
+/**
+ * Encapsulates the result of a user credential request.
+ *
+ * @property credential the user credential that can be used to authenticate to your app
+ * @throws NullPointerException If [credential] is null
+ */
+class GetCredentialResponse constructor(val credential: Credential)
diff --git a/credentials/credentials/src/main/java/androidx/credentials/GetPasswordOption.kt b/credentials/credentials/src/main/java/androidx/credentials/GetPasswordOption.kt
new file mode 100644
index 0000000..920cbf2
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/GetPasswordOption.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.credentials
+
+/** A request to retrieve the user's saved application password from their password provider. */
+class GetPasswordOption : GetCredentialOption()
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/PasswordCredential.kt b/credentials/credentials/src/main/java/androidx/credentials/PasswordCredential.kt
new file mode 100644
index 0000000..252f4a1
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/PasswordCredential.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.credentials
+
+/**
+ * Represents the user's password credential granted by the user for app sign-in.
+ *
+ * @property id the user id associated with the password
+ * @property password the password
+ * @throws NullPointerException If [id] is null
+ * @throws NullPointerException If [password] is null
+ * @throws IllegalArgumentException If [password] is empty
+ */
+class PasswordCredential constructor(
+ val id: String,
+ val password: String,
+) : Credential() {
+
+ init {
+ require(password.isNotEmpty()) { "password should not be empty" }
+ }
+}
diff --git a/datastore/datastore-multiprocess/lint-baseline.xml b/datastore/datastore-multiprocess/lint-baseline.xml
deleted file mode 100644
index 7b459a2..0000000
--- a/datastore/datastore-multiprocess/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?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="NewApi"
- message="Implicit cast from `ParcelFileDescriptor` to `Closeable` requires API level 16 (current min is 14)"
- errorLine1=" ).use {"
- errorLine2=" ~~~">
- <location
- file="src/main/java/androidx/datastore/multiprocess/SharedCounter.kt"/>
- </issue>
-
-</issues>
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index ce5e0d0..6550261 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -126,6 +126,7 @@
docs(project(":core:uwb:uwb-rxjava3"))
docs(project(":credentials:credentials"))
docs(project(":credentials:credentials-play-services-auth"))
+ docs(project(":credentials:credentials-provider"))
docs(project(":cursoradapter:cursoradapter"))
docs(project(":customview:customview"))
docs(project(":customview:customview-poolingcontainer"))
diff --git a/glance/glance/src/test/kotlin/androidx/glance/color/ColorProvidersTest.kt b/glance/glance/src/test/kotlin/androidx/glance/color/ColorProvidersTest.kt
index 370949f..a8bdf7a 100644
--- a/glance/glance/src/test/kotlin/androidx/glance/color/ColorProvidersTest.kt
+++ b/glance/glance/src/test/kotlin/androidx/glance/color/ColorProvidersTest.kt
@@ -21,7 +21,7 @@
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
import androidx.test.core.app.ApplicationProvider
-import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
@@ -33,6 +33,7 @@
private val context = ApplicationProvider.getApplicationContext<Context>()
@Test
+ @Config(sdk = [Build.VERSION_CODES.R])
fun testGlanceMatchMaterial3Colors() {
val lightColors = mapOf(
androidx.glance.R.color.glance_colorPrimary to
@@ -94,7 +95,7 @@
}
@Test
- @Config(qualifiers = "night")
+ @Config(qualifiers = "night", sdk = [Build.VERSION_CODES.R])
fun testGlanceMatchMaterial3NightColors() {
val darkColors = mapOf(
androidx.glance.R.color.glance_colorPrimary to
@@ -280,8 +281,17 @@
}
private fun assertColor(@ColorRes source: Int, @ColorRes target: Int) {
- assertThat(ContextCompat.getColor(context, source)).isEqualTo(
- ContextCompat.getColor(context, target)
- )
+ val sourceColor = ContextCompat.getColor(context, source)
+ val targetColor = ContextCompat.getColor(context, target)
+
+ val sourceHex = String.format("0x%08X", sourceColor)
+ val targetHex = String.format("0x%08X", targetColor)
+
+ val sourceName = context.resources.getResourceEntryName(source)
+ val targetName = context.resources.getResourceEntryName(target)
+
+ val message = "$sourceName is $sourceHex but $targetName is $targetHex"
+
+ assertWithMessage(message).that(sourceColor).isEqualTo(targetColor)
}
}
\ No newline at end of file
diff --git a/graphics/graphics-core/api/current.txt b/graphics/graphics-core/api/current.txt
index 1fe1a05..781c97c 100644
--- a/graphics/graphics-core/api/current.txt
+++ b/graphics/graphics-core/api/current.txt
@@ -28,7 +28,11 @@
method public boolean awaitForever();
method public void close();
method public static androidx.graphics.lowlatency.SyncFenceCompat createNativeSyncFence(androidx.graphics.opengl.egl.EGLSpec egl);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public long getSignalTime();
+ method public boolean isValid();
field public static final androidx.graphics.lowlatency.SyncFenceCompat.Companion Companion;
+ field public static final long SIGNAL_TIME_INVALID = -1L; // 0xffffffffffffffffL
+ field public static final long SIGNAL_TIME_PENDING = 9223372036854775807L; // 0x7fffffffffffffffL
}
public static final class SyncFenceCompat.Companion {
diff --git a/graphics/graphics-core/api/public_plus_experimental_current.txt b/graphics/graphics-core/api/public_plus_experimental_current.txt
index 1fe1a05..781c97c 100644
--- a/graphics/graphics-core/api/public_plus_experimental_current.txt
+++ b/graphics/graphics-core/api/public_plus_experimental_current.txt
@@ -28,7 +28,11 @@
method public boolean awaitForever();
method public void close();
method public static androidx.graphics.lowlatency.SyncFenceCompat createNativeSyncFence(androidx.graphics.opengl.egl.EGLSpec egl);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public long getSignalTime();
+ method public boolean isValid();
field public static final androidx.graphics.lowlatency.SyncFenceCompat.Companion Companion;
+ field public static final long SIGNAL_TIME_INVALID = -1L; // 0xffffffffffffffffL
+ field public static final long SIGNAL_TIME_PENDING = 9223372036854775807L; // 0x7fffffffffffffffL
}
public static final class SyncFenceCompat.Companion {
diff --git a/graphics/graphics-core/api/restricted_current.txt b/graphics/graphics-core/api/restricted_current.txt
index d2ba87f..141298c 100644
--- a/graphics/graphics-core/api/restricted_current.txt
+++ b/graphics/graphics-core/api/restricted_current.txt
@@ -28,7 +28,11 @@
method public boolean awaitForever();
method public void close();
method public static androidx.graphics.lowlatency.SyncFenceCompat createNativeSyncFence(androidx.graphics.opengl.egl.EGLSpec egl);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public long getSignalTime();
+ method public boolean isValid();
field public static final androidx.graphics.lowlatency.SyncFenceCompat.Companion Companion;
+ field public static final long SIGNAL_TIME_INVALID = -1L; // 0xffffffffffffffffL
+ field public static final long SIGNAL_TIME_PENDING = 9223372036854775807L; // 0x7fffffffffffffffL
}
public static final class SyncFenceCompat.Companion {
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/GLFrontBufferedRendererTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/GLFrontBufferedRendererTest.kt
index bb0bd74..246dced 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/GLFrontBufferedRendererTest.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/GLFrontBufferedRendererTest.kt
@@ -39,7 +39,6 @@
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
@@ -279,7 +278,6 @@
}
@Test
- @Ignore("b/244755709")
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
fun testRenderFrontBufferSeveralTimes() {
if (!deviceSupportsNativeAndroidFence()) {
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/LineRenderer.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/LineRenderer.kt
new file mode 100644
index 0000000..e80f18e
--- /dev/null
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/LineRenderer.kt
@@ -0,0 +1,166 @@
+/*
+ * 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.graphics.lowlatency
+
+import android.opengl.GLES20
+import java.nio.ByteBuffer
+import java.nio.ByteOrder
+import java.nio.FloatBuffer
+import org.junit.Assert.assertEquals
+
+/**
+ * OpenGL Renderer class responsible for drawing lines
+ */
+class LineRenderer {
+
+ private var mVertexShader: Int = -1
+ private var mFragmentShader: Int = -1
+ private var mGlProgram: Int = -1
+
+ private var mPositionHandle: Int = -1
+ private var mMvpMatrixHandle: Int = -1
+
+ private var mVertexBuffer: FloatBuffer? = null
+ private val mLineCoords = FloatArray(6)
+
+ fun initialize() {
+ release()
+ mVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VertexShaderCode)
+ mFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FragmentShaderCode)
+
+ mGlProgram = GLES20.glCreateProgram()
+ assertEquals(GLES20.GL_NO_ERROR, GLES20.glGetError())
+
+ GLES20.glAttachShader(mGlProgram, mVertexShader)
+ assertEquals(GLES20.GL_NO_ERROR, GLES20.glGetError())
+ GLES20.glAttachShader(mGlProgram, mFragmentShader)
+ assertEquals(GLES20.GL_NO_ERROR, GLES20.glGetError())
+
+ GLES20.glLinkProgram(mGlProgram)
+ assertEquals(GLES20.GL_NO_ERROR, GLES20.glGetError())
+
+ val bb: ByteBuffer =
+ ByteBuffer.allocateDirect( // (number of coordinate values * 4 bytes per float)
+ LineCoordsSize * 4
+ )
+ // use the device hardware's native byte order
+ bb.order(ByteOrder.nativeOrder())
+
+ // create a floating point buffer from the ByteBuffer
+ mVertexBuffer = bb.asFloatBuffer().apply {
+ put(mLineCoords)
+ position(0)
+ }
+
+ mPositionHandle = GLES20.glGetAttribLocation(mGlProgram, vPosition)
+ assertEquals(GLES20.GL_NO_ERROR, GLES20.glGetError())
+
+ mMvpMatrixHandle = GLES20.glGetUniformLocation(mGlProgram, uMVPMatrix)
+ assertEquals(GLES20.GL_NO_ERROR, GLES20.glGetError())
+ }
+
+ fun release() {
+ if (mVertexShader != -1) {
+ GLES20.glDeleteShader(mVertexShader)
+ mVertexShader = -1
+ }
+
+ if (mFragmentShader != -1) {
+ GLES20.glDeleteShader(mFragmentShader)
+ mFragmentShader = -1
+ }
+
+ if (mGlProgram != -1) {
+ GLES20.glDeleteProgram(mGlProgram)
+ mGlProgram = -1
+ }
+ }
+
+ fun drawLines(mvpMatrix: FloatArray, lines: FloatArray) {
+ assertEquals(GLES20.GL_NO_ERROR, GLES20.glGetError())
+ GLES20.glUseProgram(mGlProgram)
+
+ val buff = FloatBuffer.allocate(2)
+ GLES20.glGetFloatv(GLES20.GL_ALIASED_LINE_WIDTH_RANGE, buff)
+ GLES20.glLineWidth(100.0f)
+
+ GLES20.glEnableVertexAttribArray(mPositionHandle)
+
+ GLES20.glUniformMatrix4fv(mMvpMatrixHandle, 1, false, mvpMatrix, 0)
+
+ mVertexBuffer?.let { buffer ->
+ for (i in 0 until lines.size step 4) {
+ mLineCoords[0] = lines[i]
+ mLineCoords[1] = lines[i + 1]
+ mLineCoords[2] = 0f
+ mLineCoords[3] = lines[i + 2]
+ mLineCoords[4] = lines[i + 3]
+ mLineCoords[5] = 0f
+ buffer.put(mLineCoords)
+ buffer.position(0)
+ }
+
+ // Prepare the triangle coordinate data
+ GLES20.glVertexAttribPointer(
+ mPositionHandle, CoordsPerVertex,
+ GLES20.GL_FLOAT, false,
+ VertexStride, buffer
+ )
+ GLES20.glDrawArrays(GLES20.GL_LINES, 0, VertexCount)
+
+ GLES20.glDisableVertexAttribArray(mPositionHandle)
+ assertEquals(GLES20.GL_NO_ERROR, GLES20.glGetError())
+ }
+ }
+
+ companion object {
+
+ const val CoordsPerVertex = 3
+ const val LineCoordsSize = 6
+ private val VertexCount: Int = LineCoordsSize / CoordsPerVertex
+ private val VertexStride: Int = CoordsPerVertex * 4 // 4 bytes per vertex
+
+ private const val uMVPMatrix = "uMVPMatrix"
+ private const val vPosition = "vPosition"
+ private const val VertexShaderCode =
+ """
+ uniform mat4 $uMVPMatrix;
+ attribute vec4 $vPosition;
+ void main() { // the matrix must be included as a modifier of gl_Position
+ gl_Position = $uMVPMatrix * $vPosition;
+ }
+ """
+
+ private const val FragmentShaderCode =
+ """
+ precision highp float;
+
+ void main() {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ }
+ """
+
+ fun loadShader(type: Int, shaderCode: String?): Int {
+ val shader = GLES20.glCreateShader(type)
+
+ GLES20.glShaderSource(shader, shaderCode)
+ GLES20.glCompileShader(shader)
+
+ return shader
+ }
+ }
+}
\ No newline at end of file
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/SyncStrategyTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/SyncStrategyTest.kt
new file mode 100644
index 0000000..d836469
--- /dev/null
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/SyncStrategyTest.kt
@@ -0,0 +1,122 @@
+/*
+ * 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.graphics.lowlatency
+
+import android.opengl.EGL14
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.graphics.opengl.egl.EGLConfigAttributes
+import androidx.graphics.opengl.egl.EGLManager
+import androidx.graphics.opengl.egl.EGLSpec
+import androidx.graphics.opengl.egl.EGLVersion
+import androidx.graphics.opengl.egl.supportsNativeAndroidFence
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import org.junit.Assert
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class SyncStrategyTest {
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun testSyncStrategy_Always() {
+ val egl = createAndSetupEGLManager(EGLSpec.V14)
+ if (egl.supportsNativeAndroidFence()) {
+ val strategy = SyncStrategy.ALWAYS
+ val fence = strategy.createSyncFence(egl.eglSpec)
+ assertTrue(fence != null)
+ fence?.close()
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.Q)
+ @Test
+ fun testSyncStrategy_onFirstShow_FrontBufferUsageOff_Invisible() {
+ val egl = createAndSetupEGLManager(EGLSpec.V14)
+ if (egl.supportsNativeAndroidFence()) {
+ val strategy = FrontBufferSyncStrategy(false)
+ val fence = strategy.createSyncFence(EGLSpec.V14)
+ assertTrue(fence != null)
+ fence?.close()
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.Q)
+ @Test
+ fun testSyncStrategy_onFirstShow_FrontBufferUsageOff_Visible() {
+ val egl = createAndSetupEGLManager(EGLSpec.V14)
+ if (egl.supportsNativeAndroidFence()) {
+ val strategy = FrontBufferSyncStrategy(false)
+ strategy.setVisible(true)
+ val fence = strategy.createSyncFence(EGLSpec.V14)
+ assertTrue(fence == null)
+ fence?.close()
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.Q)
+ @Test
+ fun testSyncStrategy_onFirstShow_FrontBufferUsageOn_Invisible() {
+ val egl = createAndSetupEGLManager(EGLSpec.V14)
+ if (egl.supportsNativeAndroidFence()) {
+ val strategy = FrontBufferSyncStrategy(true)
+ val fence = strategy.createSyncFence(egl.eglSpec)
+ assertTrue(fence != null)
+ fence?.close()
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.Q)
+ @Test
+ fun testSyncStrategy_onFirstShow_FrontBufferUsageOn_Visible() {
+ val egl = createAndSetupEGLManager(EGLSpec.V14)
+ if (egl.supportsNativeAndroidFence()) {
+ val strategy = FrontBufferSyncStrategy(true)
+ strategy.setVisible(true)
+ val fence = strategy.createSyncFence(EGLSpec.V14)
+ assertTrue(fence == null)
+ fence?.close()
+ }
+ }
+
+ // Helper method to create and initialize an EGLManager
+ fun createAndSetupEGLManager(eglSpec: EGLSpec = EGLSpec.V14): EGLManager {
+ val egl = EGLManager(eglSpec)
+ Assert.assertEquals(EGLVersion.Unknown, egl.eglVersion)
+ Assert.assertEquals(EGL14.EGL_NO_CONTEXT, egl.eglContext)
+
+ egl.initialize()
+
+ val config = egl.loadConfig(EGLConfigAttributes.RGBA_8888)
+ if (config == null) {
+ Assert.fail("Config 888 should be supported")
+ }
+
+ egl.createContext(config!!)
+ return egl
+ }
+
+ // Helper method to release EGLManager
+ fun releaseEGLManager(egl: EGLManager) {
+ egl.release()
+ Assert.assertEquals(EGLVersion.Unknown, egl.eglVersion)
+ Assert.assertEquals(EGL14.EGL_NO_CONTEXT, egl.eglContext)
+ }
+}
\ No newline at end of file
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/GLRendererTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/GLRendererTest.kt
index 7831516..b89bbad0 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/GLRendererTest.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/GLRendererTest.kt
@@ -27,6 +27,7 @@
import android.opengl.EGL14
import android.opengl.EGLSurface
import android.opengl.GLES20
+import android.opengl.Matrix
import android.os.Build
import android.os.Handler
import android.os.HandlerThread
@@ -37,6 +38,7 @@
import androidx.annotation.RequiresApi
import androidx.annotation.WorkerThread
import androidx.graphics.lowlatency.HardwareBufferRenderer
+import androidx.graphics.lowlatency.LineRenderer
import androidx.graphics.lowlatency.RenderBuffer
import androidx.graphics.lowlatency.SyncFenceCompat
import androidx.graphics.opengl.egl.EGLManager
@@ -63,7 +65,6 @@
@RunWith(AndroidJUnit4::class)
@SmallTest
class GLRendererTest {
-
@Test
fun testStartAfterStop() {
with(GLRenderer()) {
@@ -812,6 +813,7 @@
val teardownLatch = CountDownLatch(1)
val glRenderer = GLRenderer().apply { start() }
var renderBuffer: RenderBuffer? = null
+ var status: Boolean? = false
val callbacks = object : HardwareBufferRenderer.RenderCallbacks {
override fun obtainRenderBuffer(egl: EGLSpec): RenderBuffer =
@@ -832,7 +834,11 @@
GLES20.glFlush()
}
- override fun onDrawComplete(renderBuffer: RenderBuffer) {
+ override fun onDrawComplete(
+ renderBuffer: RenderBuffer,
+ syncFenceCompat: SyncFenceCompat?
+ ) {
+ status = syncFenceCompat?.await(3000)
renderLatch.countDown()
}
}
@@ -846,6 +852,11 @@
var hardwareBuffer: HardwareBuffer? = null
try {
assertTrue(renderLatch.await(3000, TimeUnit.MILLISECONDS))
+ assert(status != null)
+ status?.let {
+ assertTrue(it)
+ }
+
hardwareBuffer = renderBuffer?.hardwareBuffer
if (hardwareBuffer != null) {
val colorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_SRGB)
@@ -869,6 +880,114 @@
}
}
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
+ fun testHardwareBufferRendererWithSyncFence() {
+ if (!deviceSupportsNativeAndroidFence()) {
+ // If the Android device does not support the corresponding
+ // EGL Extensions to obtain native Android fence objects from EGLSync
+ // instances then skip this test as we cannot guarantee consistency
+ // for front buffered rendering
+ return
+ }
+
+ val width = 10
+ val height = 10
+ val renderLatch = CountDownLatch(1)
+ val teardownLatch = CountDownLatch(1)
+
+ val glRenderer = GLRenderer().apply { start() }
+ var startTime = Long.MAX_VALUE
+ var signalTime = 0L
+
+ val renderer =
+ object : HardwareBufferRenderer.RenderCallbacks, GLRenderer.EGLContextCallback {
+ private val mMVPMatrix = FloatArray(16)
+ private val mLines = FloatArray(4)
+ private val mLineRenderer = LineRenderer()
+ var mRenderBuffer: RenderBuffer? = null
+
+ @WorkerThread
+ override fun onEGLContextCreated(eglManager: EGLManager) {
+ mLineRenderer.initialize()
+ }
+
+ @WorkerThread
+ override fun onEGLContextDestroyed(eglManager: EGLManager) {
+ mLineRenderer.release()
+ }
+
+ @WorkerThread
+ override fun obtainRenderBuffer(egl: EGLSpec): RenderBuffer {
+ return if (mRenderBuffer != null) {
+ mRenderBuffer!!
+ } else {
+ RenderBuffer(
+ egl,
+ HardwareBuffer.create(
+ width,
+ height,
+ HardwareBuffer.RGBA_8888,
+ 1,
+ HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
+ )
+ ).also { mRenderBuffer = it }
+ }
+ }
+
+ @WorkerThread
+ override fun onDraw(eglManager: EGLManager) {
+ startTime = System.nanoTime()
+ GLES20.glViewport(0, 0, width, height)
+ assertEquals(GLES20.GL_NO_ERROR, GLES20.glGetError())
+ Matrix.orthoM(mMVPMatrix, 0, 0f, width.toFloat(), 0f, height.toFloat(), -1f, 1f)
+ mLines[0] = 0f
+ mLines[1] = 0f
+ mLines[2] = 5f
+ mLines[3] = 5f
+ mLineRenderer.drawLines(mMVPMatrix, mLines)
+ assertEquals(GLES20.GL_NO_ERROR, GLES20.glGetError())
+ }
+
+ @WorkerThread
+ override fun onDrawComplete(
+ renderBuffer: RenderBuffer,
+ syncFenceCompat: SyncFenceCompat?
+ ) {
+ assertNotNull(syncFenceCompat)
+ assertTrue(syncFenceCompat!!.isValid())
+
+ assertEquals(GLES20.GL_NO_ERROR, GLES20.glGetError())
+
+ assertTrue(syncFenceCompat.await(3000))
+ signalTime = syncFenceCompat.getSignalTime()
+
+ renderLatch.countDown()
+ assertTrue(syncFenceCompat.getSignalTime() < System.nanoTime())
+ assertTrue(syncFenceCompat.getSignalTime() > startTime)
+ }
+ }
+
+ glRenderer.registerEGLContextCallback(renderer)
+ val hwBufferRenderer = HardwareBufferRenderer(renderer)
+ val renderTarget =
+ glRenderer.createRenderTarget(width, height, hwBufferRenderer)
+
+ renderTarget.requestRender()
+ assertEquals(GLES20.GL_NO_ERROR, GLES20.glGetError())
+
+ try {
+ assertTrue(renderLatch.await(3000, TimeUnit.MILLISECONDS))
+ assertTrue(startTime < signalTime)
+ assertTrue(signalTime < System.nanoTime())
+ } finally {
+ glRenderer.stop(true) {
+ teardownLatch.countDown()
+ }
+ assertTrue(teardownLatch.await(3000, TimeUnit.MILLISECONDS))
+ }
+ }
+
/**
* Helper method to create a GLTestActivity instance and progress it through the Activity
* lifecycle to the resumed state so we can issue rendering commands into the corresponding
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/SyncFenceCompatTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/SyncFenceCompatTest.kt
index cac758d..60c06e7 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/SyncFenceCompatTest.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/SyncFenceCompatTest.kt
@@ -26,7 +26,9 @@
import androidx.graphics.opengl.egl.EGLSpec
import androidx.graphics.opengl.egl.EGLVersion
import androidx.graphics.opengl.egl.supportsNativeAndroidFence
+import androidx.hardware.SyncFence
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
@@ -36,26 +38,28 @@
@RunWith(AndroidJUnit4::class)
@SmallTest
-@RequiresApi(Build.VERSION_CODES.KITKAT)
+@RequiresApi(Build.VERSION_CODES.O)
class SyncFenceCompatTest {
@Test
- fun testRenderFenceCreate() {
+ fun testSyncFenceCompat_Create() {
testEglManager {
initializeWithDefaultConfig()
if (supportsNativeAndroidFence()) {
val syncFenceCompat = SyncFenceCompat.createNativeSyncFence(this.eglSpec)
+ assert(syncFenceCompat.isValid())
syncFenceCompat.close()
}
}
}
@Test
- fun testRenderFenceAwait() {
+ fun testSyncFenceCompat_Await() {
testEglManager {
initializeWithDefaultConfig()
if (supportsNativeAndroidFence()) {
val syncFenceCompat = SyncFenceCompat.createNativeSyncFence(this.eglSpec)
+ assert(syncFenceCompat.isValid())
GLES20.glFlush()
assertTrue(syncFenceCompat.await(1000))
@@ -65,13 +69,12 @@
}
@Test
- fun testRenderFenceAwaitForever() {
+ fun testSyncFenceCompat_AwaitForever() {
testEglManager {
initializeWithDefaultConfig()
if (supportsNativeAndroidFence()) {
-
val syncFenceCompat = SyncFenceCompat.createNativeSyncFence(this.eglSpec)
- GLES20.glFlush()
+ assert(syncFenceCompat.isValid())
assertTrue(syncFenceCompat.awaitForever())
syncFenceCompat.close()
@@ -79,6 +82,26 @@
}
}
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ fun testSyncFenceCompat_SignalTime() {
+ testEglManager {
+ initializeWithDefaultConfig()
+ if (supportsNativeAndroidFence()) {
+ val start = System.nanoTime()
+ val syncFenceCompat = SyncFenceCompat.createNativeSyncFence(this.eglSpec)
+ assertTrue(syncFenceCompat.isValid())
+ assertTrue(syncFenceCompat.getSignalTime() != SyncFence.SIGNAL_TIME_INVALID)
+ assertTrue(syncFenceCompat.awaitForever())
+
+ assertTrue(syncFenceCompat.getSignalTime() > start)
+ assertTrue(syncFenceCompat.getSignalTime() != SyncFenceCompat.SIGNAL_TIME_PENDING)
+
+ syncFenceCompat.close()
+ }
+ }
+ }
+
// Helper method used in testing to initialize EGL and default
// EGLConfig to the ARGB8888 configuration
private fun EGLManager.initializeWithDefaultConfig() {
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlCompatTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlCompatTest.kt
index 8f7fec9..c4dd258 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlCompatTest.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlCompatTest.kt
@@ -295,8 +295,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
assertNotNull(buffer)
@@ -343,16 +343,16 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
assertNotNull(buffer)
val buffer2 =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.GREEN
)
assertNotNull(buffer2)
@@ -387,6 +387,114 @@
}
@Test
+ fun testTransactionSetBuffer_nullFence() {
+ val scenario = ActivityScenario.launch(SurfaceControlWrapperTestActivity::class.java)
+ .moveToState(
+ Lifecycle.State.CREATED
+ ).onActivity {
+ val callback = object : SurfaceHolderCallback() {
+ override fun surfaceCreated(sh: SurfaceHolder) {
+ val scCompat = SurfaceControlCompat
+ .Builder()
+ .setParent(it.getSurfaceView())
+ .setName("SurfaceControlCompatTest")
+ .build()
+
+ // Buffer colorspace is RGBA, so Color.BLUE will be visually Red
+ val buffer =
+ SurfaceControlUtils.getSolidBuffer(
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
+ Color.BLUE
+ )
+ assertNotNull(buffer)
+
+ SurfaceControlCompat.Transaction()
+ .setBuffer(scCompat, buffer, null)
+ .setVisibility(
+ scCompat,
+ true
+ ).commit()
+ }
+ }
+
+ it.addSurface(it.mSurfaceView, callback)
+ }
+
+ scenario.moveToState(Lifecycle.State.RESUMED).onActivity {
+ SurfaceControlUtils.validateOutput { bitmap ->
+ val coord = intArrayOf(0, 0)
+ it.mSurfaceView.getLocationOnScreen(coord)
+ Color.RED == bitmap.getPixel(coord[0], coord[1])
+ }
+ }
+ }
+
+ @Test
+ fun testTransactionSetBuffer_simpleFence() {
+ var eglManager: EGLManager? = null
+ val scenario = ActivityScenario.launch(SurfaceControlWrapperTestActivity::class.java)
+ .moveToState(
+ Lifecycle.State.CREATED
+ ).onActivity {
+ val manager = EGLManager().apply {
+ initialize()
+ val config = loadConfig(EGLConfigAttributes.RGBA_8888)
+ if (config == null) {
+ fail("Config 8888 should be supported")
+ }
+ createContext(config!!)
+ }
+ eglManager = manager
+
+ val callback = object : SurfaceHolderCallback() {
+ override fun surfaceCreated(sh: SurfaceHolder) {
+ val scCompat = SurfaceControlCompat
+ .Builder()
+ .setParent(it.getSurfaceView())
+ .setName("SurfaceControlCompatTest")
+ .build()
+
+ // Buffer colorspace is RGBA, so Color.BLUE will be visually Red
+ val buffer =
+ SurfaceControlUtils.getSolidBuffer(
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
+ Color.BLUE
+ )
+ assertNotNull(buffer)
+
+ val fence = if (manager.supportsNativeAndroidFence()) {
+ SyncFenceCompat.createNativeSyncFence(manager.eglSpec)
+ } else {
+ null
+ }
+ SurfaceControlCompat.Transaction()
+ .setBuffer(scCompat, buffer, fence)
+ .setVisibility(
+ scCompat,
+ true
+ ).commit()
+ }
+ }
+
+ it.addSurface(it.mSurfaceView, callback)
+ }
+
+ scenario.moveToState(Lifecycle.State.RESUMED).onActivity {
+ try {
+ SurfaceControlUtils.validateOutput { bitmap ->
+ val coord = intArrayOf(0, 0)
+ it.mSurfaceView.getLocationOnScreen(coord)
+ Color.RED == bitmap.getPixel(coord[0], coord[1])
+ }
+ } finally {
+ eglManager?.release()
+ }
+ }
+ }
+
+ @Test
fun testTransactionSetBuffer_nullCallback() {
val scenario = ActivityScenario.launch(SurfaceControlWrapperTestActivity::class.java)
.moveToState(
@@ -403,8 +511,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
assertNotNull(buffer)
@@ -447,8 +555,8 @@
val buffer =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.GREEN
)
assertNotNull(buffer)
@@ -456,8 +564,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer2 =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
assertNotNull(buffer2)
@@ -506,24 +614,24 @@
val buffer =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.GREEN
)
assertNotNull(buffer)
val buffer2 =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.GREEN
)
assertNotNull(buffer2)
val buffer3 =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
assertNotNull(buffer3)
@@ -562,75 +670,6 @@
}
@Test
- fun testTransactionSetBuffer_withSyncFence() {
- val releaseLatch = CountDownLatch(1)
- val egl = createAndSetupEGLManager(EGLSpec.V14)
- if (egl.supportsNativeAndroidFence()) {
- val syncFenceCompat = SyncFenceCompat.createNativeSyncFence(egl.eglSpec)
- val scenario = ActivityScenario.launch(SurfaceControlWrapperTestActivity::class.java)
- .moveToState(
- Lifecycle.State.CREATED
- ).onActivity {
- val callback = object : SurfaceHolderCallback() {
- override fun surfaceCreated(sh: SurfaceHolder) {
- val scCompat = SurfaceControlCompat
- .Builder()
- .setParent(it.getSurfaceView())
- .setName("SurfaceControlCompatTest")
- .build()
-
- val buffer =
- SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
- Color.GREEN
- )
- assertNotNull(buffer)
-
- // Buffer colorspace is RGBA, so Color.BLUE will be visually Red
- val buffer2 =
- SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
- Color.BLUE
- )
- assertNotNull(buffer2)
-
- SurfaceControlCompat.Transaction()
- .setBuffer(
- scCompat,
- buffer,
- syncFenceCompat,
- ) {
- releaseLatch.countDown()
- }
- .setVisibility(scCompat, true)
- .commit()
- SurfaceControlCompat.Transaction()
- .setBuffer(scCompat, buffer2)
- .setVisibility(scCompat, true)
- .commit()
- }
- }
-
- it.addSurface(it.mSurfaceView, callback)
- }
-
- scenario.moveToState(Lifecycle.State.RESUMED).onActivity {
- assertTrue(releaseLatch.await(3000, TimeUnit.MILLISECONDS))
- assertTrue(syncFenceCompat.await(3000))
- SurfaceControlUtils.validateOutput { bitmap ->
- val coord = intArrayOf(0, 0)
- it.mSurfaceView.getLocationOnScreen(coord)
- Color.RED == bitmap.getPixel(coord[0], coord[1])
- }
-
- releaseEGLManager(egl)
- }
- }
- }
-
- @Test
fun testTransactionSetVisibility_show() {
val scenario = ActivityScenario.launch(SurfaceControlWrapperTestActivity::class.java)
.moveToState(
@@ -647,8 +686,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
assertNotNull(buffer)
@@ -691,8 +730,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
assertNotNull(buffer)
@@ -743,8 +782,8 @@
.setBuffer(
scCompat1,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
)
@@ -753,8 +792,8 @@
.setBuffer(
scCompat2,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.GREEN
)
)
@@ -800,8 +839,8 @@
.setBuffer(
scCompat1,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.GREEN
)
)
@@ -810,8 +849,8 @@
.setBuffer(
scCompat2,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
)
@@ -857,8 +896,8 @@
.setBuffer(
scCompat1,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
)
@@ -867,8 +906,8 @@
.setBuffer(
scCompat2,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.GREEN
)
)
@@ -907,13 +946,18 @@
SurfaceControlCompat.Transaction()
.setDamageRegion(
scCompat,
- Region(0, 0, it.DEFAULT_WIDTH, it.DEFAULT_HEIGHT)
+ Region(
+ 0,
+ 0,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT
+ )
)
.setBuffer(
scCompat,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
)
@@ -957,8 +1001,8 @@
.setBuffer(
scCompat,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
)
@@ -995,8 +1039,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer = SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
@@ -1039,8 +1083,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer = SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
SurfaceControlCompat.Transaction()
@@ -1082,8 +1126,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer = SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
SurfaceControlCompat.Transaction()
@@ -1141,8 +1185,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer = SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
SurfaceControlCompat.Transaction()
@@ -1182,8 +1226,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer = SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlWrapperTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlWrapperTest.kt
index 2bafbee..80bfb12 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlWrapperTest.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlWrapperTest.kt
@@ -315,8 +315,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
assertNotNull(buffer)
@@ -372,16 +372,16 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
assertNotNull(buffer)
val buffer2 =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.GREEN
)
assertNotNull(buffer2)
@@ -433,8 +433,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
assertNotNull(buffer)
@@ -480,8 +480,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer =
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
assertNotNull(buffer)
@@ -536,8 +536,8 @@
.setBuffer(
scCompat1,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
)
@@ -545,8 +545,8 @@
.setBuffer(
scCompat2,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.GREEN
)
)
@@ -594,8 +594,8 @@
.setBuffer(
scCompat1,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.GREEN
)
)
@@ -603,8 +603,8 @@
.setBuffer(
scCompat2,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
)
@@ -652,8 +652,8 @@
.setBuffer(
scCompat1,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
)
@@ -661,8 +661,8 @@
.setBuffer(
scCompat2,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.GREEN
)
)
@@ -703,13 +703,18 @@
.addTransactionCompletedListener(listener)
.setDamageRegion(
scCompat,
- Region(0, 0, it.DEFAULT_WIDTH, it.DEFAULT_HEIGHT)
+ Region(
+ 0,
+ 0,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT
+ )
)
.setBuffer(
scCompat,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
)
@@ -755,8 +760,8 @@
.setBuffer(
scCompat,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
)
@@ -798,8 +803,8 @@
.setBuffer(
scCompat,
SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
)
@@ -838,8 +843,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer = SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
SurfaceControlWrapper.Transaction()
@@ -883,8 +888,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer = SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
SurfaceControlWrapper.Transaction()
@@ -929,8 +934,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer = SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
SurfaceControlWrapper.Transaction()
@@ -991,8 +996,8 @@
// Buffer colorspace is RGBA, so Color.BLUE will be visually Red
val buffer = SurfaceControlUtils.getSolidBuffer(
- it.DEFAULT_WIDTH,
- it.DEFAULT_HEIGHT,
+ SurfaceControlWrapperTestActivity.DEFAULT_WIDTH,
+ SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT,
Color.BLUE
)
SurfaceControlWrapper.Transaction()
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlWrapperTestActivity.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlWrapperTestActivity.kt
index 962cce7..b99dad2 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlWrapperTestActivity.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlWrapperTestActivity.kt
@@ -27,8 +27,10 @@
lateinit var mSurfaceView: SurfaceView
lateinit var mFrameLayout: FrameLayout
lateinit var mLayoutParams: FrameLayout.LayoutParams
- var DEFAULT_WIDTH = 100
- var DEFAULT_HEIGHT = 100
+ companion object {
+ val DEFAULT_WIDTH = 100
+ val DEFAULT_HEIGHT = 100
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/GLFrontBufferedRenderer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/GLFrontBufferedRenderer.kt
index e623c73..1089720 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/GLFrontBufferedRenderer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/GLFrontBufferedRenderer.kt
@@ -71,7 +71,31 @@
* be synchronized with the [SurfaceControlCompat.Transaction] to show/hide visibility of the
* front buffered layer as well as updating double buffered layers
*/
- private val mCallback = callback
+ private val mCallback = object : Callback<T> by callback {
+ @WorkerThread
+ override fun onDoubleBufferedLayerRenderComplete(
+ frontBufferedLayerSurfaceControl: SurfaceControlCompat,
+ transaction: SurfaceControlCompat.Transaction
+ ) {
+ mFrontBufferSyncStrategy.setVisible(false)
+ callback.onDoubleBufferedLayerRenderComplete(
+ frontBufferedLayerSurfaceControl,
+ transaction
+ )
+ }
+
+ @WorkerThread
+ override fun onFrontBufferedLayerRenderComplete(
+ frontBufferedLayerSurfaceControl: SurfaceControlCompat,
+ transaction: SurfaceControlCompat.Transaction
+ ) {
+ mFrontBufferSyncStrategy.setVisible(true)
+ callback.onFrontBufferedLayerRenderComplete(
+ frontBufferedLayerSurfaceControl,
+ transaction
+ )
+ }
+ }
/**
* [GLRenderer.EGLContextCallback]s used to release the corresponding [RenderBufferPool]
@@ -157,6 +181,12 @@
private var mFrontBufferedLayerSurfaceControl: SurfaceControlCompat? = null
/**
+ * [FrontBufferSyncStrategy] used for [HardwareBufferRenderer] to conditionally decide
+ * when to create a [SyncFenceCompat] for transaction calls.
+ */
+ private val mFrontBufferSyncStrategy: FrontBufferSyncStrategy
+
+ /**
* Width of the layers to render. Only if the size changes to we re-initialize the internal
* state of the [GLFrontBufferedRenderer]
*/
@@ -200,6 +230,17 @@
*/
private var mIsReleased = false
+ /**
+ * Cached value to store what [HardwareBuffer] usage flags are supported on the device.
+ */
+ private val mHardwareBufferUsageFlags: Long
+
+ /**
+ * Flag to determine if [HardwareBuffer.USAGE_FRONT_BUFFER] is supported or not on
+ * the device
+ */
+ private val mSupportsFrontBufferUsage: Boolean
+
init {
mParentRenderLayer.setParentLayerCallbacks(mParentLayerCallback)
val renderer = if (glRenderer == null) {
@@ -216,6 +257,13 @@
mDoubleBufferedLayerRenderTarget =
mParentRenderLayer.createRenderTarget(renderer, mCallback)
mGLRenderer = renderer
+
+ mHardwareBufferUsageFlags = obtainHardwareBufferUsageFlags()
+
+ mSupportsFrontBufferUsage =
+ (mHardwareBufferUsageFlags and HardwareBuffer.USAGE_FRONT_BUFFER) != 0L
+
+ mFrontBufferSyncStrategy = FrontBufferSyncStrategy(mSupportsFrontBufferUsage)
}
internal fun update(width: Int, height: Int) {
@@ -233,7 +281,7 @@
width,
height,
format = HardwareBuffer.RGBA_8888,
- usage = obtainHardwareBufferUsageFlags(),
+ usage = mHardwareBufferUsageFlags,
maxPoolSize = 5
)
@@ -289,8 +337,10 @@
mParentBufferParamQueue.add(param)
mFrontBufferedRenderTarget?.requestRender()
} else {
- Log.w(TAG, "Attempt to render to front buffered layer when " +
- "GLFrontBufferedRenderer has been released")
+ Log.w(
+ TAG, "Attempt to render to front buffered layer when " +
+ "GLFrontBufferedRenderer has been released"
+ )
}
}
@@ -318,8 +368,10 @@
mDoubleBufferedLayerRenderTarget?.requestRender()
mFrontBufferedLayerRenderer?.clear()
} else {
- Log.w(TAG, "Attempt to render to the double buffered layer when " +
- "GLFrontBufferedRenderer has been released")
+ Log.w(
+ TAG, "Attempt to render to the double buffered layer when " +
+ "GLFrontBufferedRenderer has been released"
+ )
}
}
@@ -393,58 +445,68 @@
private fun createFrontBufferedLayerRenderer(
frontBufferedLayerSurfaceControl: SurfaceControlCompat
- ) = HardwareBufferRenderer(
- object : HardwareBufferRenderer.RenderCallbacks {
+ ): HardwareBufferRenderer {
+ return HardwareBufferRenderer(
+ object : HardwareBufferRenderer.RenderCallbacks {
- @WorkerThread
- override fun obtainRenderBuffer(egl: EGLSpec): RenderBuffer {
- var buffer = mFrontLayerBuffer
- if (buffer == null) {
- // Allocate and persist a RenderBuffer instance across frames
- buffer = mBufferPool?.obtain(egl).also { mFrontLayerBuffer = it }
- ?: throw IllegalArgumentException("Unable to obtain RenderBuffer")
+ @WorkerThread
+ override fun obtainRenderBuffer(egl: EGLSpec): RenderBuffer {
+ var buffer = mFrontLayerBuffer
+ if (buffer == null) {
+ // Allocate and persist a RenderBuffer instance across frames
+ buffer = mBufferPool?.obtain(egl).also { mFrontLayerBuffer = it }
+ ?: throw IllegalArgumentException("Unable to obtain RenderBuffer")
+ }
+ return buffer
}
- return buffer
- }
- @WorkerThread
- override fun onDraw(eglManager: EGLManager) {
- try {
- // Explicitly call remove in order to delineate between scenarios where
- // no parameters are provided and the consumer explicitly supports nullable
- // parameters.
- // If poll was used instead, we would not be able to determine if the nullable
- // parameter was because there were no items in the queue or the consumer
- // explicitly provided null as a placeholder
- mCallback.onDrawFrontBufferedLayer(eglManager, mFrontBufferQueueParams.remove())
- } catch (_: NoSuchElementException) {
- // Skip rendering if we have been told to render but we do not have parameters
- // Because the call to render to the front buffer takes in a parameter we should
- // not run into this scenario.
+ @WorkerThread
+ override fun onDraw(eglManager: EGLManager) {
+ try {
+ // Explicitly call remove in order to delineate between scenarios where
+ // no parameters are provided and the consumer explicitly supports nullable
+ // parameters.
+ // If poll was used instead, we would not be able to determine if the nullable
+ // parameter was because there were no items in the queue or the consumer
+ // explicitly provided null as a placeholder
+ mCallback.onDrawFrontBufferedLayer(
+ eglManager,
+ mFrontBufferQueueParams.remove()
+ )
+ } catch (_: NoSuchElementException) {
+ // Skip rendering if we have been told to render but we do not have parameters
+ // Because the call to render to the front buffer takes in a parameter we should
+ // not run into this scenario.
+ }
}
- }
- @WorkerThread
- override fun onDrawComplete(renderBuffer: RenderBuffer) {
- val transaction = SurfaceControlCompat.Transaction()
- // Make this layer the top most layer
- .setLayer(frontBufferedLayerSurfaceControl, Integer.MAX_VALUE)
- .setBuffer(
- frontBufferedLayerSurfaceControl,
- renderBuffer.hardwareBuffer,
- null
+ @WorkerThread
+ override fun onDrawComplete(
+ renderBuffer: RenderBuffer,
+ syncFenceCompat: SyncFenceCompat?
+ ) {
+ val transaction = SurfaceControlCompat.Transaction()
+ // Make this layer the top most layer
+ .setLayer(frontBufferedLayerSurfaceControl, Integer.MAX_VALUE)
+ .setBuffer(
+ frontBufferedLayerSurfaceControl,
+ renderBuffer.hardwareBuffer,
+ syncFenceCompat
+ )
+ .setVisibility(frontBufferedLayerSurfaceControl, true)
+ mParentRenderLayer.buildReparentTransaction(
+ frontBufferedLayerSurfaceControl, transaction
)
- .setVisibility(frontBufferedLayerSurfaceControl, true)
- mParentRenderLayer.buildReparentTransaction(
- frontBufferedLayerSurfaceControl, transaction)
- mCallback.onFrontBufferedLayerRenderComplete(
- frontBufferedLayerSurfaceControl,
- transaction
- )
- transaction.commit()
- }
- }
- )
+ mCallback.onFrontBufferedLayerRenderComplete(
+ frontBufferedLayerSurfaceControl,
+ transaction
+ )
+ transaction.commit()
+ }
+ },
+ mFrontBufferSyncStrategy
+ )
+ }
private fun clearParamQueues() {
mFrontBufferQueueParams.clear()
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/HardwareBufferRenderer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/HardwareBufferRenderer.kt
index 288c3e6..14fb6b9 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/HardwareBufferRenderer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/HardwareBufferRenderer.kt
@@ -34,7 +34,8 @@
*/
@RequiresApi(Build.VERSION_CODES.O)
internal class HardwareBufferRenderer(
- private val hardwareBufferRendererCallbacks: RenderCallbacks
+ private val hardwareBufferRendererCallbacks: RenderCallbacks,
+ private val syncStrategy: SyncStrategy = SyncStrategy.ALWAYS
) : GLRenderer.RenderCallback {
private val mClear = AtomicBoolean(false)
@@ -63,13 +64,12 @@
} else {
hardwareBufferRendererCallbacks.onDraw(eglManager)
}
- GLES20.glFlush()
- syncFenceCompat = egl.createNativeSyncFence()
- syncFenceCompat.awaitForever()
+ syncFenceCompat = syncStrategy.createSyncFence(egl)
+
// At this point the HardwareBuffer has the contents of the GL rendering
// Create a surface Control transaction to dispatch this request
- hardwareBufferRendererCallbacks.onDrawComplete(buffer)
+ hardwareBufferRendererCallbacks.onDrawComplete(buffer, syncFenceCompat)
} finally {
syncFenceCompat?.close()
}
@@ -98,6 +98,71 @@
* Callback when [onDraw] is complete and the contents of the draw
* are reflected in the corresponding [HardwareBuffer]
*/
- fun onDrawComplete(renderBuffer: RenderBuffer)
+ fun onDrawComplete(renderBuffer: RenderBuffer, syncFenceCompat: SyncFenceCompat?)
+ }
+}
+
+/**
+ * A strategy class for deciding how to utilize [SyncFenceCompat] within
+ * [HardwareBufferRenderer.RenderCallbacks]. SyncStrategy provides default strategies for
+ * usage:
+ *
+ * [SyncStrategy.ALWAYS] will always create a [SyncFenceCompat] to pass into the render
+ * callbacks for [HardwareBufferRenderer]
+ */
+internal interface SyncStrategy {
+ /**
+ * Conditionally generates a [SyncFenceCompat] based upon implementation.
+ *
+ * @param eglSpec an [EGLSpec] object to dictate the version of EGL and make EGL calls.
+ */
+ fun createSyncFence(eglSpec: EGLSpec): SyncFenceCompat?
+
+ companion object {
+ /**
+ * [SyncStrategy] that will always create a [SyncFenceCompat] object
+ */
+ @JvmField
+ val ALWAYS = object : SyncStrategy {
+ override fun createSyncFence(eglSpec: EGLSpec): SyncFenceCompat? {
+ return eglSpec.createNativeSyncFence()
+ }
+ }
+ }
+}
+
+/**
+ * [SyncStrategy] implementation that optimizes for front buffered rendering use cases.
+ * More specifically this attempts to avoid unnecessary synchronization overhead
+ * wherever possible.
+ *
+ * This will always provide a fence if the corresponding layer transitions from
+ * an invisible to a visible state. If the layer is already visible and front
+ * buffer usage flags are support on the device, then no fence is provided. If this
+ * flag is not supported, then a fence is created and "peeked" to ensure contents
+ * are flushed to the single buffer.
+ */
+internal class FrontBufferSyncStrategy(
+ private val supportsFrontBufferUsage: Boolean
+) : SyncStrategy {
+ private var mFrontBufferVisible: Boolean = false
+
+ fun isVisible(): Boolean = mFrontBufferVisible
+
+ fun setVisible(visibility: Boolean) {
+ mFrontBufferVisible = visibility
+ }
+
+ @RequiresApi(Build.VERSION_CODES.Q)
+ override fun createSyncFence(eglSpec: EGLSpec): SyncFenceCompat? {
+ return if (!isVisible()) {
+ eglSpec.createNativeSyncFence()
+ } else if (supportsFrontBufferUsage) {
+ return null
+ } else {
+ val fence = eglSpec.createNativeSyncFence()
+ fence.close()
+ return null
+ }
}
}
\ No newline at end of file
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SurfaceViewRenderLayer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SurfaceViewRenderLayer.kt
index 460209b..22fd3f29 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SurfaceViewRenderLayer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SurfaceViewRenderLayer.kt
@@ -81,14 +81,17 @@
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
- override fun onDrawComplete(renderBuffer: RenderBuffer) {
+ override fun onDrawComplete(
+ renderBuffer: RenderBuffer,
+ syncFenceCompat: SyncFenceCompat?
+ ) {
val frontBufferedLayerSurfaceControl = mLayerCallback
- ?.getFrontBufferedLayerSurfaceControl()
+ ?.getFrontBufferedLayerSurfaceControl()
val sc = mParentSurfaceControl
- // At this point the parentSurfaceControl should already be created
- // in the surfaceChanged callback, however, if for whatever reason this
- // was not the case, create the double buffered SurfaceControl now and cache
- // it
+ // At this point the parentSurfaceControl should already be created
+ // in the surfaceChanged callback, however, if for whatever reason this
+ // was not the case, create the double buffered SurfaceControl now and cache
+ // it
?: createDoubleBufferedSurfaceControl().also {
mParentSurfaceControl = it
}
@@ -96,7 +99,7 @@
val transaction = SurfaceControlCompat.Transaction()
.setVisibility(frontBufferedLayerSurfaceControl, false)
.setVisibility(sc, true)
- .setBuffer(sc, renderBuffer.hardwareBuffer) {
+ .setBuffer(sc, renderBuffer.hardwareBuffer, syncFenceCompat) {
mLayerCallback?.getRenderBufferPool()?.release(renderBuffer)
}
@@ -106,11 +109,13 @@
)
transaction.commit()
} else {
- Log.e(TAG, "Error, no front buffered SurfaceControl available to " +
- "synchronize transaction with")
+ Log.e(
+ TAG, "Error, no front buffered SurfaceControl available to " +
+ "synchronize transaction with"
+ )
}
}
- })
+ })
surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder) {
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceCompat.kt b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceCompat.kt
index 149888b..a137794 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceCompat.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceCompat.kt
@@ -18,6 +18,7 @@
import android.opengl.EGL14
import android.opengl.EGL15
+import android.opengl.GLES20
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.graphics.opengl.egl.EGLSpec
@@ -55,12 +56,26 @@
val eglSync: EGLSyncKHR =
egl.eglCreateSyncKHR(EGLExt.EGL_SYNC_NATIVE_FENCE_ANDROID, null)
?: throw IllegalArgumentException("Unable to create sync object")
+ GLES20.glFlush()
val syncFenceCompat = SyncFenceCompat(egl.eglDupNativeFenceFDANDROID(eglSync))
egl.eglDestroySyncKHR(eglSync)
syncFenceCompat
}
}
+
+ /**
+ * An invalid signal time. Represents either the signal time for a SyncFence that isn't
+ * valid (that is, [isValid] is `false`), or if an error occurred while attempting to
+ * retrieve the signal time.
+ */
+ const val SIGNAL_TIME_INVALID: Long = -1L
+
+ /**
+ * A pending signal time. This is equivalent to the max value of a long, representing an
+ * infinitely far point in the future.
+ */
+ const val SIGNAL_TIME_PENDING: Long = Long.MAX_VALUE
}
internal constructor(syncFence: SyncFence) {
@@ -92,6 +107,22 @@
override fun close() {
mImpl.close()
}
+
+ /**
+ * Returns the time that the fence signaled in the [CLOCK_MONOTONIC] time domain.
+ * This returns [SyncFence.SIGNAL_TIME_INVALID] if the SyncFence is invalid.
+ * If the fence hasn't yet signaled, then [SyncFence.SIGNAL_TIME_PENDING] is returned.
+ */
+ @RequiresApi(Build.VERSION_CODES.O)
+ fun getSignalTime(): Long {
+ return mImpl.getSignalTime()
+ }
+
+ /**
+ * Checks if the SyncFence object is valid.
+ * @return `true` if it is valid, `false` otherwise
+ */
+ fun isValid() = mImpl.isValid()
}
/**
@@ -109,13 +140,15 @@
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
internal class SyncFenceCompatVerificationHelper private constructor() {
companion object {
+ private val mEmptyAttributes = longArrayOf(EGL14.EGL_NONE.toLong())
+
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@androidx.annotation.DoNotInline
fun createSyncFenceCompatV33(): SyncFenceCompat {
val display = EGL15.eglGetPlatformDisplay(
EGL15.EGL_PLATFORM_ANDROID_KHR,
EGL14.EGL_DEFAULT_DISPLAY.toLong(),
- longArrayOf(EGL14.EGL_NONE.toLong()),
+ mEmptyAttributes,
0
)
if (display == EGL15.EGL_NO_DISPLAY) {
@@ -129,10 +162,10 @@
val eglSync = EGL15.eglCreateSync(
display,
android.opengl.EGLExt.EGL_SYNC_NATIVE_FENCE_ANDROID,
- longArrayOf(),
+ mEmptyAttributes,
0
)
-
+ GLES20.glFlush()
val syncFenceCompat = SyncFenceCompat(
android.opengl.EGLExt.eglDupNativeFenceFDANDROID(
display,
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceImpl.kt b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceImpl.kt
index 66dc871..a0aa066 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceImpl.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceImpl.kt
@@ -16,6 +16,10 @@
package androidx.graphics.lowlatency
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.hardware.SyncFence
+
internal interface SyncFenceImpl {
/**
* Waits for a [SyncFenceImpl] to signal for up to the timeout duration
@@ -33,4 +37,18 @@
* Close the [SyncFenceImpl]
*/
fun close()
+
+ /**
+ * Returns the time that the fence signaled in the [CLOCK_MONOTONIC] time domain.
+ * This returns [SyncFence.SIGNAL_TIME_INVALID] if the SyncFence is invalid.
+ * If the fence hasn't yet signaled, then [SyncFence.SIGNAL_TIME_PENDING] is returned.
+ */
+ @RequiresApi(Build.VERSION_CODES.O)
+ fun getSignalTime(): Long
+
+ /**
+ * Checks if the SyncFence object is valid.
+ * @return `true` if it is valid, `false` otherwise
+ */
+ fun isValid(): Boolean
}
\ No newline at end of file
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceV19.kt b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceV19.kt
index 1623412..2e29eb5 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceV19.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceV19.kt
@@ -44,4 +44,19 @@
override fun close() {
mSyncFence.close()
}
+
+ /**
+ * See [SyncFenceImpl.getSignalTime]
+ */
+ @RequiresApi(Build.VERSION_CODES.O)
+ override fun getSignalTime(): Long {
+ return mSyncFence.getSignalTime()
+ }
+
+ /**
+ * See [SyncFenceImpl.isValid]
+ */
+ override fun isValid(): Boolean {
+ return mSyncFence.isValid()
+ }
}
\ No newline at end of file
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceV33.kt b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceV33.kt
index abcb1a0..1f039a3 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceV33.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SyncFenceV33.kt
@@ -45,4 +45,19 @@
override fun close() {
mSyncFence.close()
}
+
+ /**
+ * See [SyncFenceImpl.getSignalTime]
+ */
+ override fun getSignalTime(): Long {
+ return mSyncFence.signalTime
+ }
+
+ /**
+ * Checks if the SyncFence object is valid.
+ * @return `true` if it is valid, `false` otherwise
+ */
+ override fun isValid(): Boolean {
+ return mSyncFence.isValid
+ }
}
\ No newline at end of file
diff --git a/graphics/graphics-core/src/main/java/androidx/hardware/SyncFence.kt b/graphics/graphics-core/src/main/java/androidx/hardware/SyncFence.kt
index 3977a83..3963976 100644
--- a/graphics/graphics-core/src/main/java/androidx/hardware/SyncFence.kt
+++ b/graphics/graphics-core/src/main/java/androidx/hardware/SyncFence.kt
@@ -14,22 +14,6 @@
* limitations under the License.
*/
-/*
- * 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.hardware
import android.os.Build
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/utils/IntentExt.kt b/health/connect/connect-client/src/main/java/androidx/health/platform/client/utils/IntentExt.kt
index fa639aa..21dbe1f 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/utils/IntentExt.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/utils/IntentExt.kt
@@ -23,11 +23,10 @@
import androidx.annotation.RestrictTo
import androidx.health.platform.client.proto.AbstractMessageLite
-fun Intent.putProtoMessages(name: String, messages: Collection<AbstractMessageLite<*, *>>) {
+fun Intent.putProtoMessages(name: String, messages: Collection<AbstractMessageLite<*, *>>): Intent =
putByteArraysExtra(name = name, byteArrays = messages.map { it.toByteArray() })
-}
-fun Intent.putByteArraysExtra(name: String, byteArrays: Collection<ByteArray>) {
+fun Intent.putByteArraysExtra(name: String, byteArrays: Collection<ByteArray>): Intent =
putExtra(
name,
Bundle(byteArrays.size).apply {
@@ -36,7 +35,6 @@
}
},
)
-}
fun <T : AbstractMessageLite<*, *>> Intent.getProtoMessages(
name: String,
diff --git a/health/connect/connect-client/src/test/java/androidx/health/platform/client/utils/IntentExtTest.kt b/health/connect/connect-client/src/test/java/androidx/health/platform/client/utils/IntentExtTest.kt
index 58e95cb..0e117fb 100644
--- a/health/connect/connect-client/src/test/java/androidx/health/platform/client/utils/IntentExtTest.kt
+++ b/health/connect/connect-client/src/test/java/androidx/health/platform/client/utils/IntentExtTest.kt
@@ -18,6 +18,8 @@
import android.content.Intent
import android.os.Parcel
+import androidx.health.connect.client.impl.converters.records.protoDataType
+import androidx.health.platform.client.proto.DataProto.DataType
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@@ -29,10 +31,12 @@
@Test
fun byteArrays_notEmpty() {
val originalArrays = List(1024) { ByteArray(it, Int::toByte) }
- var intent = Intent()
- intent.putByteArraysExtra("key", originalArrays)
- intent = intent.serializeDeserialize()
- val deserializedArrays = intent.getByteArraysExtra("key")
+
+ val deserializedArrays =
+ Intent()
+ .putByteArraysExtra("key", originalArrays)
+ .serializeDeserialize()
+ .getByteArraysExtra("key")
assertThat(deserializedArrays?.map(ByteArray::toList))
.containsExactlyElementsIn(originalArrays.map(ByteArray::toList))
@@ -40,11 +44,11 @@
@Test
fun byteArrays_empty() {
- val originalArrays = emptyList<ByteArray>()
- var intent = Intent()
- intent.putByteArraysExtra("key", originalArrays)
- intent = intent.serializeDeserialize()
- val deserializedArrays = intent.getByteArraysExtra("key")
+ val deserializedArrays =
+ Intent()
+ .putByteArraysExtra("key", emptyList())
+ .serializeDeserialize()
+ .getByteArraysExtra("key")
assertThat(deserializedArrays).isEmpty()
}
@@ -56,6 +60,37 @@
assertThat(deserializedArrays).isNull()
}
+ @Test
+ fun protoMessages_notEmpty() {
+ val originalMessages = List(128) { protoDataType("STEPS") }
+
+ val deserializedMessages =
+ Intent()
+ .putProtoMessages("key", originalMessages)
+ .serializeDeserialize()
+ .getProtoMessages("key", DataType::parseFrom)
+
+ assertThat(deserializedMessages).containsExactlyElementsIn(originalMessages)
+ }
+
+ @Test
+ fun protoMessages_empty() {
+ val deserializedMessages =
+ Intent()
+ .putProtoMessages("key", emptyList())
+ .serializeDeserialize()
+ .getProtoMessages("key", DataType::parseFrom)
+
+ assertThat(deserializedMessages).isEmpty()
+ }
+
+ @Test
+ fun protoMessages_null() {
+ val deserializedArrays = Intent().getProtoMessages("key", DataType::parseFrom)
+
+ assertThat(deserializedArrays).isNull()
+ }
+
private fun Intent.serializeDeserialize(): Intent {
val parcel = Parcel.obtain()
writeToParcel(parcel, 0)
diff --git a/libraryversions.toml b/libraryversions.toml
index 34f03d2..44b8c15 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -140,7 +140,7 @@
WINDOW = "1.1.0-alpha04"
WINDOW_EXTENSIONS = "1.1.0-alpha02"
WINDOW_SIDECAR = "1.0.0-rc01"
-WORK = "2.8.0-alpha05"
+WORK = "2.8.0-beta01"
[groups]
ACTIVITY = { group = "androidx.activity", atomicGroupVersion = "versions.ACTIVITY" }
diff --git a/media/media/src/main/java/android/support/v4/media/session/MediaControllerCompat.java b/media/media/src/main/java/android/support/v4/media/session/MediaControllerCompat.java
index 7f71344..1b5aeef 100644
--- a/media/media/src/main/java/android/support/v4/media/session/MediaControllerCompat.java
+++ b/media/media/src/main/java/android/support/v4/media/session/MediaControllerCompat.java
@@ -222,18 +222,7 @@
* @param session The session to be controlled.
*/
public MediaControllerCompat(Context context, @NonNull MediaSessionCompat session) {
- if (session == null) {
- throw new IllegalArgumentException("session must not be null");
- }
- mToken = session.getSessionToken();
-
- if (Build.VERSION.SDK_INT >= 29) {
- mImpl = new MediaControllerImplApi29(context, mToken);
- } else if (Build.VERSION.SDK_INT >= 21) {
- mImpl = new MediaControllerImplApi21(context, mToken);
- } else {
- mImpl = new MediaControllerImplBase(mToken);
- }
+ this(context, session.getSessionToken());
}
/**
@@ -248,7 +237,9 @@
}
mToken = sessionToken;
- if (android.os.Build.VERSION.SDK_INT >= 21) {
+ if (Build.VERSION.SDK_INT >= 29) {
+ mImpl = new MediaControllerImplApi29(context, sessionToken);
+ } else if (Build.VERSION.SDK_INT >= 21) {
mImpl = new MediaControllerImplApi21(context, sessionToken);
} else {
mImpl = new MediaControllerImplBase(sessionToken);
diff --git a/media2/media2-common/lint-baseline.xml b/media2/media2-common/lint-baseline.xml
index 37f296f..d4ef3f4 100644
--- a/media2/media2-common/lint-baseline.xml
+++ b/media2/media2-common/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<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="KotlinPropertyAccess"
diff --git a/navigation/navigation-ui/api/current.txt b/navigation/navigation-ui/api/current.txt
index 9551da2..27e99a9 100644
--- a/navigation/navigation-ui/api/current.txt
+++ b/navigation/navigation-ui/api/current.txt
@@ -11,6 +11,7 @@
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;
diff --git a/navigation/navigation-ui/api/public_plus_experimental_current.txt b/navigation/navigation-ui/api/public_plus_experimental_current.txt
index 62b5ce4..7cb97e2 100644
--- a/navigation/navigation-ui/api/public_plus_experimental_current.txt
+++ b/navigation/navigation-ui/api/public_plus_experimental_current.txt
@@ -11,6 +11,7 @@
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;
diff --git a/navigation/navigation-ui/api/restricted_current.txt b/navigation/navigation-ui/api/restricted_current.txt
index 9551da2..27e99a9 100644
--- a/navigation/navigation-ui/api/restricted_current.txt
+++ b/navigation/navigation-ui/api/restricted_current.txt
@@ -11,6 +11,7 @@
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;
diff --git a/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/AppBarConfigurationTest.kt b/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/AppBarConfigurationTest.kt
index c2576ae..83c849d 100644
--- a/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/AppBarConfigurationTest.kt
+++ b/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/AppBarConfigurationTest.kt
@@ -17,10 +17,14 @@
package androidx.navigation.ui
import android.content.Context
+import androidx.appcompat.widget.Toolbar
import androidx.drawerlayout.widget.DrawerLayout
import androidx.navigation.NavController
+import androidx.navigation.NavDestinationBuilder
+import androidx.navigation.NavHostController
import androidx.navigation.createGraph
import androidx.navigation.plusAssign
+import androidx.test.annotation.UiThreadTest
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry
@@ -90,4 +94,124 @@
assertThat(appBarConfiguration.fallbackOnNavigateUpListener)
.isEqualTo(onNavigateUpListener)
}
+
+ @UiThreadTest
+ @Test
+ fun testIsTopLevelDestination_menuItemAsNestedGraph() {
+ val navController = NavHostController(context)
+ val navigator = TestNavigator()
+ navController.apply {
+ navigatorProvider.addNavigator(navigator)
+ setGraph(R.navigation.simple_graph)
+ }
+
+ val toolbar = Toolbar(context).apply {
+ inflateMenu(R.menu.menu)
+ }
+ val appBarConfig = AppBarConfiguration.Builder(
+ topLevelMenu = toolbar.menu
+ ).build()
+ // start destination of menu_item_graph, a nested graph (and start dest) inside simple_graph
+ assertThat(navController.currentDestination?.id).isEqualTo(
+ R.id.itemHome
+ )
+ // start destination of menu_item_graph which should be a topLevelDestination
+ assertThat(
+ appBarConfig.isTopLevelDestination(
+ navController.currentDestination!!
+ )
+ ).isTrue()
+ // non-starting destination within menu_item_graph
+ assertThat(
+ appBarConfig.isTopLevelDestination(
+ navController.currentDestination!!.parent!!.findNode(R.id.itemSecondDestination)!!
+ )
+ ).isFalse()
+ }
+
+ @UiThreadTest
+ @Test
+ fun testIsTopLevelDestination_menuItemAsIndividualItem() {
+ val navController = NavHostController(context)
+ val navigator = TestNavigator()
+ navController.apply {
+ navigatorProvider.addNavigator(navigator)
+ setGraph(R.navigation.simple_graph)
+ }
+
+ val toolbar = Toolbar(context).apply {
+ inflateMenu(R.menu.menu)
+ }
+ val appBarConfig = AppBarConfiguration.Builder(
+ topLevelMenu = toolbar.menu
+ ).build()
+
+ // menu_item_graph is a NavGraph. The graph id itself should not be a top level destination.
+ assertThat(
+ appBarConfig.isTopLevelDestination(
+ navController.graph.findNode(R.id.menu_item_graph)!!
+ )
+ ).isFalse()
+
+ // menu_item2 which is not a graph. Even though it is not the startDestination of
+ // its parent (simple_graph), it should be added as a topLevelDestination
+ // via AppBarConfig.Builder(menu) constructor.
+ assertThat(
+ appBarConfig.isTopLevelDestination(
+ navController.graph.findNode(R.id.menu_item2)!!
+ )
+ ).isTrue()
+ }
+
+ @UiThreadTest
+ @Test
+ fun testIsTopLevelDestination_simpleGraph() {
+ val navController = NavController(context)
+ val navGraph = navController.apply {
+ navigatorProvider += TestNavigator()
+ }.createGraph(startDestination = "1") {
+ test("1")
+ test("2")
+ }
+ navController.setGraph(navGraph, null)
+ val builder = AppBarConfiguration.Builder(navGraph)
+ val appBarConfiguration = builder.build()
+
+ assertThat(appBarConfiguration.isTopLevelDestination(
+ navController.graph.findNode("1")!!)
+ ).isTrue()
+ assertThat(
+ appBarConfiguration.isTopLevelDestination(navController.graph.findNode("2")!!)
+ ).isFalse()
+ }
+
+ @UiThreadTest
+ @Test
+ fun testIsTopLevelDestination_fromDestinationIds() {
+ val navigator = TestNavigator()
+
+ val dest1 = NavDestinationBuilder(navigator, "1").build()
+ val dest2 = NavDestinationBuilder(navigator, "2").build()
+
+ val builder = AppBarConfiguration.Builder(dest1.id, dest2.id)
+ val appBarConfiguration = builder.build()
+
+ assertThat(appBarConfiguration.isTopLevelDestination(dest1)).isTrue()
+ assertThat(appBarConfiguration.isTopLevelDestination(dest2)).isTrue()
+ }
+
+ @UiThreadTest
+ @Test
+ fun testIsTopLevelDestination_fromSetOfDestinationIds() {
+ val navigator = TestNavigator()
+
+ val dest1 = NavDestinationBuilder(navigator, "1").build()
+ val dest2 = NavDestinationBuilder(navigator, "2").build()
+
+ val builder = AppBarConfiguration.Builder(setOf(dest1.id, dest2.id))
+ val appBarConfiguration = builder.build()
+
+ assertThat(appBarConfiguration.isTopLevelDestination(dest1)).isTrue()
+ assertThat(appBarConfiguration.isTopLevelDestination(dest2)).isTrue()
+ }
}
diff --git a/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/NavigationUITest.kt b/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/NavigationUITest.kt
index 356161d..0796ff3 100644
--- a/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/NavigationUITest.kt
+++ b/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/NavigationUITest.kt
@@ -23,18 +23,14 @@
import androidx.core.content.res.TypedArrayUtils.getString
import androidx.navigation.NavController
import androidx.navigation.NavDestination
-import androidx.navigation.NavGraph
-import androidx.navigation.NavGraphNavigator
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.createGraph
-import androidx.navigation.ui.NavigationUI.matchDestinations
import androidx.test.annotation.UiThreadTest
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.testutils.TestNavigator
-import androidx.testutils.TestNavigatorProvider
import androidx.testutils.test
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -43,15 +39,6 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
class NavigationUITest {
- @Test
- fun matchDestinationsTest() {
- val destination = TestNavigator().createDestination().apply {
- id = 1
- parent = NavGraph(NavGraphNavigator(TestNavigatorProvider()))
- }
-
- assertThat(destination.matchDestinations(setOf(1, 2))).isTrue()
- }
@UiThreadTest
@Test
diff --git a/navigation/navigation-ui/src/main/java/androidx/navigation/ui/AbstractAppBarOnDestinationChangedListener.kt b/navigation/navigation-ui/src/main/java/androidx/navigation/ui/AbstractAppBarOnDestinationChangedListener.kt
index 9962d7b..3b2c798 100644
--- a/navigation/navigation-ui/src/main/java/androidx/navigation/ui/AbstractAppBarOnDestinationChangedListener.kt
+++ b/navigation/navigation-ui/src/main/java/androidx/navigation/ui/AbstractAppBarOnDestinationChangedListener.kt
@@ -26,7 +26,6 @@
import androidx.navigation.FloatingWindow
import androidx.navigation.NavController
import androidx.navigation.NavDestination
-import androidx.navigation.ui.NavigationUI.matchDestinations
import java.lang.ref.WeakReference
/**
@@ -36,9 +35,8 @@
*/
internal abstract class AbstractAppBarOnDestinationChangedListener(
private val context: Context,
- configuration: AppBarConfiguration
+ private val configuration: AppBarConfiguration
) : NavController.OnDestinationChangedListener {
- private val topLevelDestinations: Set<Int> = configuration.topLevelDestinations
private val openableLayoutWeakReference = configuration.openableLayout?.run {
WeakReference(this)
}
@@ -68,7 +66,7 @@
setTitle(label)
}
- val isTopLevelDestination = destination.matchDestinations(topLevelDestinations)
+ val isTopLevelDestination = configuration.isTopLevelDestination(destination)
if (openableLayout == null && isTopLevelDestination) {
setNavigationIcon(null, 0)
} else {
diff --git a/navigation/navigation-ui/src/main/java/androidx/navigation/ui/AppBarConfiguration.kt b/navigation/navigation-ui/src/main/java/androidx/navigation/ui/AppBarConfiguration.kt
index 252f385..827a259b 100644
--- a/navigation/navigation-ui/src/main/java/androidx/navigation/ui/AppBarConfiguration.kt
+++ b/navigation/navigation-ui/src/main/java/androidx/navigation/ui/AppBarConfiguration.kt
@@ -17,8 +17,11 @@
import android.annotation.SuppressLint
import android.view.Menu
+import android.view.MenuItem
import androidx.customview.widget.Openable
import androidx.drawerlayout.widget.DrawerLayout
+import androidx.navigation.NavDestination
+import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener
@@ -80,6 +83,31 @@
} else null
/**
+ * Determines whether a [NavDestination] is a top level destination in [AppBarConfiguration].
+ *
+ * Returns true if the [NavDestination] was added directly as a top level destination via
+ * [AppBarConfiguration.Builder] constructors such as
+ * `AppBarConfiguration.Builder(topLevelDestinationIds: Set<Int>)`.
+ * If destination was added with a [AppBarConfiguration.Builder] that could take in a graph,
+ * i.e. `AppBarConfiguration.Builder(NavGraph)` or`AppBarConfiguration.Builder(Menu)`, this
+ * helper will return true if the destination is the start destination of a graph
+ * (including nested graphs i.e. [MenuItem] that are also [NavGraph]), or an individual
+ * [MenuItem] within the [Menu].
+ *
+ * @param destination the [NavDestination] to check whether it is a topLevelDestination
+ */
+ public fun isTopLevelDestination(destination: NavDestination): Boolean {
+ return destination.hierarchy.any { parent ->
+ when (parent.id in topLevelDestinations) {
+ true -> if (parent is NavGraph) {
+ destination.id == parent.findStartDestination().id
+ } else true
+ else -> false
+ }
+ }
+ }
+
+ /**
* The Builder class for constructing new [AppBarConfiguration] instances.
*/
public class Builder {
diff --git a/navigation/navigation-ui/src/main/java/androidx/navigation/ui/NavigationUI.kt b/navigation/navigation-ui/src/main/java/androidx/navigation/ui/NavigationUI.kt
index 920eff2..9a5a17e 100644
--- a/navigation/navigation-ui/src/main/java/androidx/navigation/ui/NavigationUI.kt
+++ b/navigation/navigation-ui/src/main/java/androidx/navigation/ui/NavigationUI.kt
@@ -205,9 +205,8 @@
): Boolean {
val openableLayout = configuration.openableLayout
val currentDestination = navController.currentDestination
- val topLevelDestinations = configuration.topLevelDestinations
return if (openableLayout != null && currentDestination != null &&
- currentDestination.matchDestinations(topLevelDestinations)
+ configuration.isTopLevelDestination(currentDestination)
) {
openableLayout.open()
true
@@ -708,13 +707,4 @@
@JvmStatic
internal fun NavDestination.matchDestination(@IdRes destId: Int): Boolean =
hierarchy.any { it.id == destId }
-
- /**
- * Determines whether the given `destinationIds` match the NavDestination. This
- * handles both the default case (the destination's id is in the given ids) and the nested
- * case where the given ids is a parent/grandparent/etc of the destination.
- */
- @JvmStatic
- internal fun NavDestination.matchDestinations(destinationIds: Set<Int?>): Boolean =
- hierarchy.any { destinationIds.contains(it.id) }
}
diff --git a/navigation/navigation-ui/src/main/res/menu/menu.xml b/navigation/navigation-ui/src/main/res/menu/menu.xml
new file mode 100644
index 0000000..245cf19
--- /dev/null
+++ b/navigation/navigation-ui/src/main/res/menu/menu.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/menu_item_graph"
+ android:title="menu_item1_title" />
+ <item
+ android:id="@+id/menu_item2"
+ android:title="menu_item2_title" />
+</menu>
diff --git a/navigation/navigation-ui/src/main/res/navigation/menu_item_graph.xml b/navigation/navigation-ui/src/main/res/navigation/menu_item_graph.xml
new file mode 100644
index 0000000..4a65edc
--- /dev/null
+++ b/navigation/navigation-ui/src/main/res/navigation/menu_item_graph.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<navigation
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/menu_item_graph"
+ app:startDestination="@+id/itemHome">
+
+ <test
+ android:id="@+id/itemHome"
+ android:name="androidx.navigation.ui.androidTest.EmptyFragment">
+ <action
+ android:id="@+id/itemHome_to_itemSecondDestination"
+ app:destination="@id/itemSecondDestination" />
+ </test>
+ <test
+ android:id="@+id/itemSecondDestination"
+ android:name="androidx.navigation.ui.androidTest.EmptyFragment">
+ </test>
+</navigation>
diff --git a/navigation/navigation-ui/src/main/res/navigation/simple_graph.xml b/navigation/navigation-ui/src/main/res/navigation/simple_graph.xml
new file mode 100644
index 0000000..1fd0cd2
--- /dev/null
+++ b/navigation/navigation-ui/src/main/res/navigation/simple_graph.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<navigation
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/simple_graph"
+ app:startDestination="@+id/menu_item_graph">
+
+ <test
+ android:id="@+id/menu_item2"
+ android:name="androidx.navigation.ui.androidTest.EmptyFragment">
+ </test>
+
+ <include app:graph="@navigation/menu_item_graph"/>
+</navigation>
diff --git a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/GridLayoutManager.java b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/GridLayoutManager.java
index 01935b5..4c4aba2 100644
--- a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/GridLayoutManager.java
+++ b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/GridLayoutManager.java
@@ -964,6 +964,9 @@
/**
* Returns the final span index of the provided position.
* <p>
+ * If {@link #getOrientation()} is {@link #VERTICAL}, this is a column value.
+ * If {@link #getOrientation()} is {@link #HORIZONTAL}, this is a row value.
+ * <p>
* If you have a faster way to calculate span index for your items, you should override
* this method. Otherwise, you should enable span index cache
* ({@link #setSpanIndexCacheEnabled(boolean)}) for better performance. When caching is
@@ -1040,6 +1043,9 @@
/**
* Returns the index of the group this position belongs.
* <p>
+ * If {@link #getOrientation()} is {@link #VERTICAL}, this is a row value.
+ * If {@link #getOrientation()} is {@link #HORIZONTAL}, this is a column value.
+ * <p>
* For example, if grid has 3 columns and each item occupies 1 span, span group index
* for item 1 will be 0, item 5 will be 1.
*
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 ae1c0fb..83ccfd4 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
@@ -215,7 +215,6 @@
* @see hasNoteContainingMatch
*/
fun hasWarningContainingMatch(expectedPattern: String): DiagnosticMessagesSubject {
- shouldSucceed = false
return hasDiagnosticWithPattern(
kind = Diagnostic.Kind.WARNING,
expectedPattern = expectedPattern,
@@ -262,7 +261,6 @@
* @see hasWarningContainingMatch
*/
fun hasNoteContainingMatch(expectedPattern: String): DiagnosticMessagesSubject {
- shouldSucceed = false
return hasDiagnosticWithPattern(
kind = Diagnostic.Kind.NOTE,
expectedPattern = expectedPattern,
diff --git a/room/room-compiler-processing-testing/src/test/java/androidx/room/compiler/processing/util/DiagnosticsTest.kt b/room/room-compiler-processing-testing/src/test/java/androidx/room/compiler/processing/util/DiagnosticsTest.kt
index 30e21f1..7ded92a 100644
--- a/room/room-compiler-processing-testing/src/test/java/androidx/room/compiler/processing/util/DiagnosticsTest.kt
+++ b/room/room-compiler-processing-testing/src/test/java/androidx/room/compiler/processing/util/DiagnosticsTest.kt
@@ -39,17 +39,45 @@
}
invocation.assertCompilationResult {
hasNote("note 1")
- hasWarning("warn 1")
- hasError("error 1")
+ assertThat(shouldSucceed).isTrue()
hasNoteContaining("ote")
- hasWarningContaining("arn")
- hasErrorContaining("rror")
+ assertThat(shouldSucceed).isTrue()
hasNoteContainingMatch("ote")
- hasWarningContainingMatch("arn")
- hasErrorContainingMatch("rror")
hasNoteContainingMatch("^note \\d$")
+ assertThat(shouldSucceed).isTrue()
+
+ hasWarning("warn 1")
+ assertThat(shouldSucceed).isTrue()
+ hasWarningContaining("arn")
+ assertThat(shouldSucceed).isTrue()
+ hasWarningContainingMatch("arn")
hasWarningContainingMatch("^warn \\d$")
+ assertThat(shouldSucceed).isTrue()
+
+ hasError("error 1")
+ assertThat(shouldSucceed).isFalse()
+ hasErrorContaining("rror")
+ assertThat(shouldSucceed).isFalse()
+ hasErrorContainingMatch("rror")
hasErrorContainingMatch("^error \\d$")
+ assertThat(shouldSucceed).isFalse()
+
+ hasNote("note 1")
+ assertThat(shouldSucceed).isFalse()
+ hasNoteContaining("ote")
+ assertThat(shouldSucceed).isFalse()
+ hasNoteContainingMatch("ote")
+ hasNoteContainingMatch("^note \\d$")
+ assertThat(shouldSucceed).isFalse()
+
+ hasWarning("warn 1")
+ assertThat(shouldSucceed).isFalse()
+ hasWarningContaining("arn")
+ assertThat(shouldSucceed).isFalse()
+ hasWarningContainingMatch("arn")
+ hasWarningContainingMatch("^warn \\d$")
+ assertThat(shouldSucceed).isFalse()
+
// these should fail:
assertThat(
runCatching { hasNote("note") }.isFailure
diff --git a/room/room-migration/src/main/java/androidx/room/migration/bundle/FtsEntityBundle.kt b/room/room-migration/src/main/java/androidx/room/migration/bundle/FtsEntityBundle.kt
index b5e8ed9..ec1c6ed 100644
--- a/room/room-migration/src/main/java/androidx/room/migration/bundle/FtsEntityBundle.kt
+++ b/room/room-migration/src/main/java/androidx/room/migration/bundle/FtsEntityBundle.kt
@@ -60,6 +60,7 @@
emptyList()
)
+ @Transient
private val SHADOW_TABLE_NAME_SUFFIXES = listOf(
"_content",
"_segdir",
@@ -92,6 +93,7 @@
* Gets the list of shadow table names corresponding to the FTS virtual table.
* @return the list of names.
*/
+ @delegate:Transient
public open val shadowTableNames: List<String> by lazy {
val currentTable = this@FtsEntityBundle.tableName
buildList {
diff --git a/room/room-runtime/src/test/java/androidx/room/BuilderTest.java b/room/room-runtime/src/test/java/androidx/room/BuilderTest.java
deleted file mode 100644
index ca73919..0000000
--- a/room/room-runtime/src/test/java/androidx/room/BuilderTest.java
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.room;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.CoreMatchers.nullValue;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-import static java.util.Arrays.asList;
-
-import android.content.Context;
-
-import androidx.annotation.NonNull;
-import androidx.room.migration.Migration;
-import androidx.sqlite.db.SupportSQLiteDatabase;
-import androidx.sqlite.db.SupportSQLiteOpenHelper;
-import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory;
-
-import org.hamcrest.CoreMatchers;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.io.File;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-@SuppressWarnings({"ArraysAsListWithZeroOrOneArgument", "deprecation"})
-@RunWith(JUnit4.class)
-public class BuilderTest {
- @Test(expected = IllegalArgumentException.class)
- public void nullName() {
- //noinspection ConstantConditions
- Room.databaseBuilder(mock(Context.class), RoomDatabase.class, null).build();
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void emptyName() {
- Room.databaseBuilder(mock(Context.class), RoomDatabase.class, " ").build();
- }
-
- @Test
- public void executors_setQueryExecutor() {
- Executor executor = mock(Executor.class);
-
- TestDatabase db = Room.databaseBuilder(mock(Context.class), TestDatabase.class, "foo")
- .setQueryExecutor(executor)
- .build();
-
- assertThat(db.mDatabaseConfiguration.queryExecutor, is(executor));
- assertThat(db.mDatabaseConfiguration.transactionExecutor, is(executor));
- }
-
- @Test
- public void executors_setTransactionExecutor() {
- Executor executor = mock(Executor.class);
-
- TestDatabase db = Room.databaseBuilder(mock(Context.class), TestDatabase.class, "foo")
- .setTransactionExecutor(executor)
- .build();
-
- assertThat(db.mDatabaseConfiguration.queryExecutor, is(executor));
- assertThat(db.mDatabaseConfiguration.transactionExecutor, is(executor));
- }
-
- @Test
- public void executors_setBothExecutors() {
- Executor executor1 = mock(Executor.class);
- Executor executor2 = mock(Executor.class);
-
- TestDatabase db = Room.databaseBuilder(mock(Context.class), TestDatabase.class, "foo")
- .setQueryExecutor(executor1)
- .setTransactionExecutor(executor2)
- .build();
-
- assertThat(db.mDatabaseConfiguration.queryExecutor, is(executor1));
- assertThat(db.mDatabaseConfiguration.transactionExecutor, is(executor2));
- }
-
- @Test
- public void migration() {
- Migration m1 = new EmptyMigration(0, 1);
- Migration m2 = new EmptyMigration(1, 2);
- TestDatabase db = Room.databaseBuilder(mock(Context.class), TestDatabase.class, "foo")
- .addMigrations(m1, m2).build();
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- RoomDatabase.MigrationContainer migrations = config.migrationContainer;
- assertThat(migrations.findMigrationPath(0, 1), is(asList(m1)));
- assertThat(migrations.findMigrationPath(1, 2), is(asList(m2)));
- assertThat(migrations.findMigrationPath(0, 2), is(asList(m1, m2)));
- assertThat(migrations.findMigrationPath(2, 0), CoreMatchers.<List<Migration>>nullValue());
- assertThat(migrations.findMigrationPath(0, 3), CoreMatchers.<List<Migration>>nullValue());
- }
-
- @Test
- public void migrationOverride() {
- Migration m1 = new EmptyMigration(0, 1);
- Migration m2 = new EmptyMigration(1, 2);
- Migration m3 = new EmptyMigration(0, 1);
- TestDatabase db = Room.databaseBuilder(mock(Context.class), TestDatabase.class, "foo")
- .addMigrations(m1, m2, m3).build();
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- RoomDatabase.MigrationContainer migrations = config.migrationContainer;
- assertThat(migrations.findMigrationPath(0, 1), is(asList(m3)));
- assertThat(migrations.findMigrationPath(1, 2), is(asList(m2)));
- assertThat(migrations.findMigrationPath(0, 3), CoreMatchers.<List<Migration>>nullValue());
- }
-
- @Test
- public void migrationJump() {
- Migration m1 = new EmptyMigration(0, 1);
- Migration m2 = new EmptyMigration(1, 2);
- Migration m3 = new EmptyMigration(2, 3);
- Migration m4 = new EmptyMigration(0, 3);
- TestDatabase db = Room.databaseBuilder(mock(Context.class), TestDatabase.class, "foo")
- .addMigrations(m1, m2, m3, m4).build();
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- RoomDatabase.MigrationContainer migrations = config.migrationContainer;
- assertThat(migrations.findMigrationPath(0, 3), is(asList(m4)));
- assertThat(migrations.findMigrationPath(1, 3), is(asList(m2, m3)));
- }
-
- @Test
- public void migrationDowngrade() {
- Migration m1_2 = new EmptyMigration(1, 2);
- Migration m2_3 = new EmptyMigration(2, 3);
- Migration m3_4 = new EmptyMigration(3, 4);
- Migration m3_2 = new EmptyMigration(3, 2);
- Migration m2_1 = new EmptyMigration(2, 1);
- TestDatabase db = Room.databaseBuilder(mock(Context.class), TestDatabase.class, "foo")
- .addMigrations(m1_2, m2_3, m3_4, m3_2, m2_1).build();
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- RoomDatabase.MigrationContainer migrations = config.migrationContainer;
- assertThat(migrations.findMigrationPath(3, 2), is(asList(m3_2)));
- assertThat(migrations.findMigrationPath(3, 1), is(asList(m3_2, m2_1)));
- }
-
- @Test
- public void skipMigration() {
- Context context = mock(Context.class);
-
- TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
- .fallbackToDestructiveMigration()
- .build();
-
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- assertThat(config.requireMigration, is(false));
- }
-
- @Test
- public void fallbackToDestructiveMigrationFrom_calledOnce_migrationsNotRequiredForValues() {
- Context context = mock(Context.class);
-
- TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
- .fallbackToDestructiveMigrationFrom(1, 2).build();
-
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- assertThat(config.isMigrationRequiredFrom(1), is(false));
- assertThat(config.isMigrationRequiredFrom(2), is(false));
-
- assertThat(config.isMigrationRequired(1, 2), is(false));
- assertThat(config.isMigrationRequired(2, 3), is(false));
- }
-
- @Test
- public void fallbackToDestructiveMigrationFrom_calledTwice_migrationsNotRequiredForValues() {
- Context context = mock(Context.class);
- TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
- .fallbackToDestructiveMigrationFrom(1, 2)
- .fallbackToDestructiveMigrationFrom(3, 4)
- .build();
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
-
- assertThat(config.isMigrationRequiredFrom(1), is(false));
- assertThat(config.isMigrationRequiredFrom(2), is(false));
- assertThat(config.isMigrationRequiredFrom(3), is(false));
- assertThat(config.isMigrationRequiredFrom(4), is(false));
-
- assertThat(config.isMigrationRequired(1, 2), is(false));
- assertThat(config.isMigrationRequired(2, 3), is(false));
- assertThat(config.isMigrationRequired(3, 4), is(false));
- assertThat(config.isMigrationRequired(4, 5), is(false));
- }
-
- @Test
- public void isMigrationRequiredFrom_fallBackToDestructiveCalled_alwaysReturnsFalse() {
- Context context = mock(Context.class);
-
- TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
- .fallbackToDestructiveMigration()
- .build();
-
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- assertThat(config.isMigrationRequiredFrom(0), is(false));
- assertThat(config.isMigrationRequiredFrom(1), is(false));
- assertThat(config.isMigrationRequiredFrom(5), is(false));
- assertThat(config.isMigrationRequiredFrom(12), is(false));
- assertThat(config.isMigrationRequiredFrom(132), is(false));
-
- // Upgrades
- assertThat(config.isMigrationRequired(0, 1), is(false));
- assertThat(config.isMigrationRequired(1, 2), is(false));
- assertThat(config.isMigrationRequired(5, 6), is(false));
- assertThat(config.isMigrationRequired(7, 12), is(false));
- assertThat(config.isMigrationRequired(132, 150), is(false));
-
- // Downgrades
- assertThat(config.isMigrationRequired(1, 0), is(false));
- assertThat(config.isMigrationRequired(2, 1), is(false));
- assertThat(config.isMigrationRequired(6, 5), is(false));
- assertThat(config.isMigrationRequired(7, 12), is(false));
- assertThat(config.isMigrationRequired(150, 132), is(false));
- }
-
- @Test
- public void isMigrationRequired_destructiveMigrationOnDowngrade_returnTrueWhenUpgrading() {
- Context context = mock(Context.class);
-
- TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
- .fallbackToDestructiveMigrationOnDowngrade()
- .build();
-
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
-
- // isMigrationRequiredFrom doesn't know about downgrade only so it always returns true
- assertThat(config.isMigrationRequiredFrom(0), is(true));
- assertThat(config.isMigrationRequiredFrom(1), is(true));
- assertThat(config.isMigrationRequiredFrom(5), is(true));
- assertThat(config.isMigrationRequiredFrom(12), is(true));
- assertThat(config.isMigrationRequiredFrom(132), is(true));
-
- assertThat(config.isMigrationRequired(0, 1), is(true));
- assertThat(config.isMigrationRequired(1, 2), is(true));
- assertThat(config.isMigrationRequired(5, 6), is(true));
- assertThat(config.isMigrationRequired(7, 12), is(true));
- assertThat(config.isMigrationRequired(132, 150), is(true));
- }
-
- @Test
- public void isMigrationRequired_destructiveMigrationOnDowngrade_returnFalseWhenDowngrading() {
- Context context = mock(Context.class);
-
- TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
- .fallbackToDestructiveMigrationOnDowngrade()
- .build();
-
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
-
- // isMigrationRequiredFrom doesn't know about downgrade only so it always returns true
- assertThat(config.isMigrationRequiredFrom(0), is(true));
- assertThat(config.isMigrationRequiredFrom(1), is(true));
- assertThat(config.isMigrationRequiredFrom(5), is(true));
- assertThat(config.isMigrationRequiredFrom(12), is(true));
- assertThat(config.isMigrationRequiredFrom(132), is(true));
-
- assertThat(config.isMigrationRequired(1, 0), is(false));
- assertThat(config.isMigrationRequired(2, 1), is(false));
- assertThat(config.isMigrationRequired(6 , 5), is(false));
- assertThat(config.isMigrationRequired(12, 7), is(false));
- assertThat(config.isMigrationRequired(150, 132), is(false));
- }
-
- @Test
- public void isMigrationRequiredFrom_byDefault_alwaysReturnsTrue() {
- Context context = mock(Context.class);
-
- TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
- .build();
-
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- assertThat(config.isMigrationRequiredFrom(0), is(true));
- assertThat(config.isMigrationRequiredFrom(1), is(true));
- assertThat(config.isMigrationRequiredFrom(5), is(true));
- assertThat(config.isMigrationRequiredFrom(12), is(true));
- assertThat(config.isMigrationRequiredFrom(132), is(true));
-
- // Upgrades
- assertThat(config.isMigrationRequired(0, 1), is(true));
- assertThat(config.isMigrationRequired(1, 2), is(true));
- assertThat(config.isMigrationRequired(5, 6), is(true));
- assertThat(config.isMigrationRequired(7, 12), is(true));
- assertThat(config.isMigrationRequired(132, 150), is(true));
-
- // Downgrades
- assertThat(config.isMigrationRequired(1, 0), is(true));
- assertThat(config.isMigrationRequired(2, 1), is(true));
- assertThat(config.isMigrationRequired(6, 5), is(true));
- assertThat(config.isMigrationRequired(7, 12), is(true));
- assertThat(config.isMigrationRequired(150, 132), is(true));
- }
-
- @Test
- public void isMigrationRequiredFrom_fallBackToDestFromCalled_falseForProvidedValues() {
- Context context = mock(Context.class);
-
- TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
- .fallbackToDestructiveMigrationFrom(1, 4, 81)
- .build();
-
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- assertThat(config.isMigrationRequiredFrom(1), is(false));
- assertThat(config.isMigrationRequiredFrom(4), is(false));
- assertThat(config.isMigrationRequiredFrom(81), is(false));
-
- assertThat(config.isMigrationRequired(1, 2), is(false));
- assertThat(config.isMigrationRequired(4, 8), is(false));
- assertThat(config.isMigrationRequired(81, 90), is(false));
- }
-
- @Test
- public void isMigrationRequiredFrom_fallBackToDestFromCalled_trueForNonProvidedValues() {
- Context context = mock(Context.class);
-
- TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
- .fallbackToDestructiveMigrationFrom(1, 4, 81)
- .build();
-
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- assertThat(config.isMigrationRequiredFrom(2), is(true));
- assertThat(config.isMigrationRequiredFrom(3), is(true));
- assertThat(config.isMigrationRequiredFrom(73), is(true));
-
- assertThat(config.isMigrationRequired(2, 3), is(true));
- assertThat(config.isMigrationRequired(3, 4), is(true));
- assertThat(config.isMigrationRequired(73, 80), is(true));
- }
-
- @Test
- public void autoMigrationShouldBeAddedToMigrations_WhenManualDowngradeMigrationIsPresent() {
- Context context = mock(Context.class);
-
- BuilderTest_TestDatabase_Impl db =
- (BuilderTest_TestDatabase_Impl) Room.inMemoryDatabaseBuilder(context,
- TestDatabase.class)
- .addMigrations(new EmptyMigration(1, 0))
- .build();
-
- DatabaseConfiguration config = db.mDatabaseConfiguration;
-
- assertThat(config.migrationContainer.findMigrationPath(1, 2), is(db.mAutoMigrations));
- }
-
- @Test
- public void fallbackToDestructiveMigrationOnDowngrade_withProvidedValues_falseForDowngrades() {
- Context context = mock(Context.class);
-
- TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
- .fallbackToDestructiveMigrationOnDowngrade()
- .fallbackToDestructiveMigrationFrom(2, 4).build();
-
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
-
- assertThat(config.isMigrationRequired(1, 2), is(true));
- assertThat(config.isMigrationRequired(2, 3), is(false));
- assertThat(config.isMigrationRequired(3, 4), is(true));
- assertThat(config.isMigrationRequired(4, 5), is(false));
- assertThat(config.isMigrationRequired(5, 6), is(true));
-
- assertThat(config.isMigrationRequired(2, 1), is(false));
- assertThat(config.isMigrationRequired(3, 2), is(false));
- assertThat(config.isMigrationRequired(4, 3), is(false));
- assertThat(config.isMigrationRequired(5, 4), is(false));
- assertThat(config.isMigrationRequired(6, 5), is(false));
- }
-
- @Test
- public void createBasic() {
- Context context = mock(Context.class);
- TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class).build();
- assertThat(db, instanceOf(BuilderTest_TestDatabase_Impl.class));
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- assertThat(config, notNullValue());
- assertThat(config.context, is(context));
- assertThat(config.name, is(nullValue()));
- assertThat(config.allowMainThreadQueries, is(false));
- assertThat(config.journalMode, is(RoomDatabase.JournalMode.TRUNCATE));
- assertThat(config.sqliteOpenHelperFactory,
- instanceOf(FrameworkSQLiteOpenHelperFactory.class));
- }
-
- @Test
- public void createAllowMainThread() {
- Context context = mock(Context.class);
- TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
- .allowMainThreadQueries()
- .build();
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- assertThat(config.allowMainThreadQueries, is(true));
- }
-
- @Test
- public void createWriteAheadLogging() {
- Context context = mock(Context.class);
- TestDatabase db = Room.databaseBuilder(context, TestDatabase.class, "foo")
- .setJournalMode(RoomDatabase.JournalMode.WRITE_AHEAD_LOGGING).build();
- assertThat(db, instanceOf(BuilderTest_TestDatabase_Impl.class));
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- assertThat(config.journalMode, is(RoomDatabase.JournalMode.WRITE_AHEAD_LOGGING));
- }
-
- @Test
- public void createWithFactoryAndVersion() {
- Context context = mock(Context.class);
- SupportSQLiteOpenHelper.Factory factory = mock(SupportSQLiteOpenHelper.Factory.class);
-
- TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
- .openHelperFactory(factory)
- .build();
- assertThat(db, instanceOf(BuilderTest_TestDatabase_Impl.class));
- DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
- assertThat(config, notNullValue());
- assertThat(config.sqliteOpenHelperFactory, is(factory));
- }
-
- @Test
- public void createFromAssetAndFromFile() {
- Exception exception = null;
- try {
- Room.databaseBuilder(mock(Context.class), TestDatabase.class, "foo")
- .createFromAsset("assets-path")
- .createFromFile(new File("not-a--real-file"))
- .build();
- fail("Build should have thrown");
- } catch (Exception e) {
- exception = e;
- }
- assertThat(exception, instanceOf(IllegalArgumentException.class));
- assertThat(exception.getMessage(),
- containsString(
- "More than one of createFromAsset(), createFromInputStream(), and "
- + "createFromFile() were called on this Builder"));
- }
-
- @Test
- public void createInMemoryFromAsset() {
- Exception exception = null;
- try {
- Room.inMemoryDatabaseBuilder(mock(Context.class), TestDatabase.class)
- .createFromAsset("assets-path")
- .build();
- fail("Build should have thrown");
- } catch (Exception e) {
- exception = e;
- }
- assertThat(exception, instanceOf(IllegalArgumentException.class));
- assertThat(exception.getMessage(),
- containsString("Cannot create from asset or file for an in-memory"));
- }
-
- @Test
- public void createInMemoryFromFile() {
- Exception exception = null;
- try {
- Room.inMemoryDatabaseBuilder(mock(Context.class), TestDatabase.class)
- .createFromFile(new File("not-a--real-file"))
- .build();
- fail("Build should have thrown");
- } catch (Exception e) {
- exception = e;
- }
- assertThat(exception, instanceOf(IllegalArgumentException.class));
- assertThat(exception.getMessage(),
- containsString("Cannot create from asset or file for an in-memory"));
- }
-
- abstract static class TestDatabase extends RoomDatabase {
-
- DatabaseConfiguration mDatabaseConfiguration;
-
- @Override
- public void init(@NonNull DatabaseConfiguration configuration) {
- super.init(configuration);
- mDatabaseConfiguration = configuration;
- }
- }
-
- static class EmptyMigration extends Migration {
- EmptyMigration(int start, int end) {
- super(start, end);
- }
-
- @Override
- public void migrate(@NonNull SupportSQLiteDatabase database) {
- }
- }
-
-}
diff --git a/room/room-runtime/src/test/java/androidx/room/BuilderTest.kt b/room/room-runtime/src/test/java/androidx/room/BuilderTest.kt
new file mode 100644
index 0000000..cd2f9f1
--- /dev/null
+++ b/room/room-runtime/src/test/java/androidx/room/BuilderTest.kt
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.room
+
+import android.content.Context
+import androidx.room.Room.databaseBuilder
+import androidx.room.Room.inMemoryDatabaseBuilder
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+import androidx.sqlite.db.SupportSQLiteOpenHelper
+import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.util.concurrent.Executor
+import org.junit.Assert
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.kotlin.mock
+
+@RunWith(JUnit4::class)
+class BuilderTest {
+ @Test
+ fun nullName() {
+ try {
+ databaseBuilder(
+ mock(), RoomDatabase::class.java, null
+ ).build()
+ } catch (e: IllegalArgumentException) {
+ assertThat(e.message).isEqualTo(
+ "Cannot build a database with null or empty name. If you are trying to create an " +
+ "in memory database, use Room.inMemoryDatabaseBuilder"
+ )
+ }
+ }
+
+ @Test
+ fun emptyName() {
+ try {
+ databaseBuilder(
+ mock(), RoomDatabase::class.java, " "
+ ).build()
+ } catch (e: IllegalArgumentException) {
+ assertThat(e.message).isEqualTo(
+ "Cannot build a database with null or empty name. If you are trying to create an " +
+ "in memory database, use Room.inMemoryDatabaseBuilder"
+ )
+ }
+ }
+
+ @Test
+ fun executors_setQueryExecutor() {
+ val executor: Executor = mock()
+ val db = databaseBuilder(
+ mock(), TestDatabase::class.java, "foo"
+ ).setQueryExecutor(executor).build()
+
+ assertThat(db.mDatabaseConfiguration.queryExecutor).isEqualTo(executor)
+ assertThat(db.mDatabaseConfiguration.transactionExecutor).isEqualTo(executor)
+ }
+
+ @Test
+ fun executors_setTransactionExecutor() {
+ val executor: Executor = mock()
+ val db = databaseBuilder(
+ mock(), TestDatabase::class.java, "foo"
+ ).setTransactionExecutor(executor).build()
+
+ assertThat(db.mDatabaseConfiguration.queryExecutor).isEqualTo(executor)
+ assertThat(db.mDatabaseConfiguration.transactionExecutor).isEqualTo(executor)
+ }
+
+ @Test
+ fun executors_setBothExecutors() {
+ val executor1: Executor = mock()
+ val executor2: Executor = mock()
+ val db = databaseBuilder(
+ mock(), TestDatabase::class.java, "foo"
+ ).setQueryExecutor(executor1).setTransactionExecutor(executor2).build()
+
+ assertThat(db.mDatabaseConfiguration.queryExecutor).isEqualTo(executor1)
+ assertThat(db.mDatabaseConfiguration.transactionExecutor).isEqualTo(executor2)
+ }
+
+ @Test
+ fun migration() {
+ val m1: Migration = EmptyMigration(0, 1)
+ val m2: Migration = EmptyMigration(1, 2)
+ val db = databaseBuilder(
+ mock(), TestDatabase::class.java, "foo"
+ ).addMigrations(m1, m2).build()
+
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ val migrations = config.migrationContainer
+
+ assertThat(migrations.findMigrationPath(0, 1)).containsExactlyElementsIn(listOf(m1))
+ assertThat(migrations.findMigrationPath(1, 2)).containsExactlyElementsIn(listOf(m2))
+ assertThat(migrations.findMigrationPath(0, 2))
+ .containsExactlyElementsIn(listOf(m1, m2))
+ assertThat(migrations.findMigrationPath(2, 0)).isNull()
+ assertThat(migrations.findMigrationPath(0, 3)).isNull()
+ }
+
+ @Test
+ fun migrationOverride() {
+ val m1: Migration = EmptyMigration(0, 1)
+ val m2: Migration = EmptyMigration(1, 2)
+ val m3: Migration = EmptyMigration(0, 1)
+ val db = databaseBuilder(
+ mock(), TestDatabase::class.java, "foo"
+ ).addMigrations(m1, m2, m3).build()
+
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ val migrations = config.migrationContainer
+
+ assertThat(migrations.findMigrationPath(0, 1)).containsExactlyElementsIn(listOf(m3))
+ assertThat(migrations.findMigrationPath(1, 2)).containsExactlyElementsIn(listOf(m2))
+ assertThat(migrations.findMigrationPath(0, 3)).isNull()
+ }
+
+ @Test
+ fun migrationJump() {
+ val m1: Migration = EmptyMigration(0, 1)
+ val m2: Migration = EmptyMigration(1, 2)
+ val m3: Migration = EmptyMigration(2, 3)
+ val m4: Migration = EmptyMigration(0, 3)
+ val db = databaseBuilder(
+ mock(), TestDatabase::class.java, "foo"
+ ).addMigrations(m1, m2, m3, m4).build()
+
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ val migrations = config.migrationContainer
+
+ assertThat(migrations.findMigrationPath(0, 3)).containsExactlyElementsIn(listOf(m4))
+ assertThat(migrations.findMigrationPath(1, 3))
+ .containsExactlyElementsIn(listOf(m2, m3))
+ }
+
+ @Test
+ fun migrationDowngrade() {
+ val m1_2: Migration = EmptyMigration(1, 2)
+ val m2_3: Migration = EmptyMigration(2, 3)
+ val m3_4: Migration = EmptyMigration(3, 4)
+ val m3_2: Migration = EmptyMigration(3, 2)
+ val m2_1: Migration = EmptyMigration(2, 1)
+ val db = databaseBuilder(
+ mock(), TestDatabase::class.java, "foo"
+ )
+ .addMigrations(m1_2, m2_3, m3_4, m3_2, m2_1).build()
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ val migrations = config.migrationContainer
+ assertThat(migrations.findMigrationPath(3, 2))
+ .containsExactlyElementsIn(listOf(m3_2))
+ assertThat(migrations.findMigrationPath(3, 1))
+ .containsExactlyElementsIn(listOf(m3_2, m2_1))
+ }
+
+ @Test
+ fun skipMigration() {
+ val context: Context = mock()
+ val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java)
+ .fallbackToDestructiveMigration()
+ .build()
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ assertThat(config.requireMigration).isFalse()
+ }
+
+ @Test
+ fun fallbackToDestructiveMigrationFrom_calledOnce_migrationsNotRequiredForValues() {
+ val context: Context = mock()
+ val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java)
+ .fallbackToDestructiveMigrationFrom(1, 2).build()
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ assertThat(config.isMigrationRequired(1, 2)).isFalse()
+ assertThat(config.isMigrationRequired(2, 3)).isFalse()
+ }
+
+ @Test
+ fun fallbackToDestructiveMigrationFrom_calledTwice_migrationsNotRequiredForValues() {
+ val context: Context = mock()
+ val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java)
+ .fallbackToDestructiveMigrationFrom(1, 2)
+ .fallbackToDestructiveMigrationFrom(3, 4)
+ .build()
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ assertThat(config.isMigrationRequired(1, 2)).isFalse()
+ assertThat(config.isMigrationRequired(2, 3)).isFalse()
+ assertThat(config.isMigrationRequired(3, 4)).isFalse()
+ assertThat(config.isMigrationRequired(4, 5)).isFalse()
+ }
+
+ @Test
+ fun isMigrationRequiredFrom_fallBackToDestructiveCalled_alwaysReturnsFalse() {
+ val context: Context = mock()
+ val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java)
+ .fallbackToDestructiveMigration()
+ .build()
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+
+ assertThat(config.isMigrationRequired(0, 1)).isFalse()
+ assertThat(config.isMigrationRequired(1, 2)).isFalse()
+ assertThat(config.isMigrationRequired(5, 6)).isFalse()
+ assertThat(config.isMigrationRequired(7, 12)).isFalse()
+ assertThat(config.isMigrationRequired(132, 150)).isFalse()
+
+ assertThat(config.isMigrationRequired(1, 0)).isFalse()
+ assertThat(config.isMigrationRequired(2, 1)).isFalse()
+ assertThat(config.isMigrationRequired(6, 5)).isFalse()
+ assertThat(config.isMigrationRequired(7, 12)).isFalse()
+ assertThat(config.isMigrationRequired(150, 132)).isFalse()
+ }
+
+ // isMigrationRequiredFrom doesn't know about downgrade only so it always returns true
+ @Test
+ fun isMigrationRequired_destructiveMigrationOnDowngrade_returnTrueWhenUpgrading() {
+ val context: Context = mock()
+ val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java)
+ .fallbackToDestructiveMigrationOnDowngrade()
+ .build()
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+
+ // isMigrationRequiredFrom doesn't know about downgrade only so it always returns true
+ assertThat(config.isMigrationRequired(0, 1)).isTrue()
+ assertThat(config.isMigrationRequired(1, 2)).isTrue()
+ assertThat(config.isMigrationRequired(5, 6)).isTrue()
+ assertThat(config.isMigrationRequired(7, 12)).isTrue()
+ assertThat(config.isMigrationRequired(132, 150)).isTrue()
+ }
+
+ // isMigrationRequiredFrom doesn't know about downgrade only so it always returns true
+ @Test
+ fun isMigrationRequired_destructiveMigrationOnDowngrade_returnFalseWhenDowngrading() {
+ val context: Context = mock()
+ val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java)
+ .fallbackToDestructiveMigrationOnDowngrade()
+ .build()
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+
+ // isMigrationRequiredFrom doesn't know about downgrade only so it always returns true
+ assertThat(config.isMigrationRequired(1, 0)).isFalse()
+ assertThat(config.isMigrationRequired(2, 1)).isFalse()
+ assertThat(config.isMigrationRequired(6, 5)).isFalse()
+ assertThat(config.isMigrationRequired(12, 7)).isFalse()
+ assertThat(config.isMigrationRequired(150, 132)).isFalse()
+ }
+
+ @Test
+ fun isMigrationRequiredFrom_byDefault_alwaysReturnsTrue() {
+ val context: Context = mock()
+ val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java)
+ .build()
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+
+ assertThat(config.isMigrationRequired(0, 1)).isTrue()
+ assertThat(config.isMigrationRequired(1, 2)).isTrue()
+ assertThat(config.isMigrationRequired(5, 6)).isTrue()
+ assertThat(config.isMigrationRequired(7, 12)).isTrue()
+ assertThat(config.isMigrationRequired(132, 150)).isTrue()
+
+ assertThat(config.isMigrationRequired(1, 0)).isTrue()
+ assertThat(config.isMigrationRequired(2, 1)).isTrue()
+ assertThat(config.isMigrationRequired(6, 5)).isTrue()
+ assertThat(config.isMigrationRequired(7, 12)).isTrue()
+ assertThat(config.isMigrationRequired(150, 132)).isTrue()
+ }
+
+ @Test
+ fun isMigrationRequiredFrom_fallBackToDestFromCalled_falseForProvidedValues() {
+ val context: Context = mock()
+ val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java)
+ .fallbackToDestructiveMigrationFrom(1, 4, 81)
+ .build()
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ assertThat(config.isMigrationRequired(1, 2)).isFalse()
+ assertThat(config.isMigrationRequired(4, 8)).isFalse()
+ assertThat(config.isMigrationRequired(81, 90)).isFalse()
+ }
+
+ @Test
+ fun isMigrationRequiredFrom_fallBackToDestFromCalled_trueForNonProvidedValues() {
+ val context: Context = mock()
+ val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java)
+ .fallbackToDestructiveMigrationFrom(1, 4, 81)
+ .build()
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ assertThat(config.isMigrationRequired(2, 3)).isTrue()
+ assertThat(config.isMigrationRequired(3, 4)).isTrue()
+ assertThat(config.isMigrationRequired(73, 80)).isTrue()
+ }
+
+ @Test
+ fun autoMigrationShouldBeAddedToMigrations_WhenManualDowngradeMigrationIsPresent() {
+ val context: Context = mock()
+ val db = inMemoryDatabaseBuilder(
+ context,
+ TestDatabase::class.java
+ )
+ .addMigrations(EmptyMigration(1, 0))
+ .build() as BuilderTest_TestDatabase_Impl
+ val config: DatabaseConfiguration = db.mDatabaseConfiguration
+ assertThat(
+ config.migrationContainer.findMigrationPath(1, 2)).isEqualTo((db.mAutoMigrations)
+ )
+ }
+
+ @Test
+ fun fallbackToDestructiveMigrationOnDowngrade_withProvidedValues_falseForDowngrades() {
+ val context: Context = mock()
+ val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java)
+ .fallbackToDestructiveMigrationOnDowngrade()
+ .fallbackToDestructiveMigrationFrom(2, 4).build()
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ assertThat(config.isMigrationRequired(1, 2)).isTrue()
+ assertThat(config.isMigrationRequired(2, 3)).isFalse()
+ assertThat(config.isMigrationRequired(3, 4)).isTrue()
+ assertThat(config.isMigrationRequired(4, 5)).isFalse()
+ assertThat(config.isMigrationRequired(5, 6)).isTrue()
+ assertThat(config.isMigrationRequired(2, 1)).isFalse()
+ assertThat(config.isMigrationRequired(3, 2)).isFalse()
+ assertThat(config.isMigrationRequired(4, 3)).isFalse()
+ assertThat(config.isMigrationRequired(5, 4)).isFalse()
+ assertThat(config.isMigrationRequired(6, 5)).isFalse()
+ }
+
+ @Test
+ fun createBasic() {
+ val context: Context = mock()
+ val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java).build()
+ assertThat(db).isInstanceOf(BuilderTest_TestDatabase_Impl::class.java)
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ assertThat(config).isNotNull()
+ assertThat(config.context).isEqualTo(context)
+ assertThat(config.name).isNull()
+ assertThat(config.allowMainThreadQueries).isFalse()
+ assertThat(config.journalMode).isEqualTo(RoomDatabase.JournalMode.TRUNCATE)
+ assertThat(config.sqliteOpenHelperFactory)
+ .isInstanceOf(FrameworkSQLiteOpenHelperFactory::class.java)
+ }
+
+ @Test
+ fun createAllowMainThread() {
+ val context: Context = mock()
+ val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java)
+ .allowMainThreadQueries()
+ .build()
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ assertThat(config.allowMainThreadQueries).isTrue()
+ }
+
+ @Test
+ fun createWriteAheadLogging() {
+ val context: Context = mock()
+ val db = databaseBuilder(context, TestDatabase::class.java, "foo")
+ .setJournalMode(RoomDatabase.JournalMode.WRITE_AHEAD_LOGGING).build()
+ assertThat(db).isInstanceOf(BuilderTest_TestDatabase_Impl::class.java)
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ assertThat(config.journalMode).isEqualTo(RoomDatabase.JournalMode.WRITE_AHEAD_LOGGING)
+ }
+
+ @Test
+ fun createWithFactoryAndVersion() {
+ val context: Context = mock()
+ val factory: SupportSQLiteOpenHelper.Factory = mock()
+ val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java)
+ .openHelperFactory(factory)
+ .build()
+ assertThat(db).isInstanceOf(BuilderTest_TestDatabase_Impl::class.java)
+ val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
+ assertThat(config).isNotNull()
+ assertThat(config.sqliteOpenHelperFactory).isEqualTo(factory)
+ }
+
+ @Test
+ fun createFromAssetAndFromFile() {
+ var exception: Exception? = null
+ try {
+ databaseBuilder(
+ mock(),
+ TestDatabase::class.java,
+ "foo"
+ )
+ .createFromAsset("assets-path")
+ .createFromFile(File("not-a--real-file"))
+ .build()
+ Assert.fail("Build should have thrown")
+ } catch (e: Exception) {
+ exception = e
+ }
+ assertThat(exception).isInstanceOf(IllegalArgumentException::class.java)
+ assertThat(exception).hasMessageThat().contains("More than one of createFromAsset(), " +
+ "createFromInputStream(), and createFromFile() were called on this Builder")
+ }
+
+ @Test
+ fun createInMemoryFromAsset() {
+ var exception: Exception? = null
+ try {
+ inMemoryDatabaseBuilder(
+ mock(),
+ TestDatabase::class.java
+ )
+ .createFromAsset("assets-path")
+ .build()
+ Assert.fail("Build should have thrown")
+ } catch (e: Exception) {
+ exception = e
+ }
+ assertThat(exception).isInstanceOf(IllegalArgumentException::class.java)
+ assertThat(exception).hasMessageThat().contains(
+ "Cannot create from asset or file for an in-memory"
+ )
+ }
+
+ @Test
+ fun createInMemoryFromFile() {
+ var exception: Exception? = null
+ try {
+ inMemoryDatabaseBuilder(
+ mock(),
+ TestDatabase::class.java
+ )
+ .createFromFile(File("not-a--real-file"))
+ .build()
+ Assert.fail("Build should have thrown")
+ } catch (e: Exception) {
+ exception = e
+ }
+ assertThat(exception).isInstanceOf(IllegalArgumentException::class.java)
+ assertThat(exception).hasMessageThat().contains(
+ "Cannot create from asset or file for an in-memory"
+ )
+ }
+
+ internal abstract class TestDatabase : RoomDatabase() {
+ lateinit var mDatabaseConfiguration: DatabaseConfiguration
+ override fun init(configuration: DatabaseConfiguration) {
+ super.init(configuration)
+ mDatabaseConfiguration = configuration
+ }
+ }
+
+ internal class EmptyMigration(start: Int, end: Int) : Migration(start, end) {
+ override fun migrate(database: SupportSQLiteDatabase) {}
+ }
+}
diff --git a/room/room-runtime/src/test/java/androidx/room/BuilderTest_TestDatabase_Impl.java b/room/room-runtime/src/test/java/androidx/room/BuilderTest_TestDatabase_Impl.java
deleted file mode 100644
index f475782..0000000
--- a/room/room-runtime/src/test/java/androidx/room/BuilderTest_TestDatabase_Impl.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.room;
-
-import androidx.annotation.NonNull;
-import androidx.room.migration.AutoMigrationSpec;
-import androidx.room.migration.Migration;
-import androidx.sqlite.db.SupportSQLiteOpenHelper;
-
-import org.mockito.Mockito;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-public class BuilderTest_TestDatabase_Impl extends BuilderTest.TestDatabase {
- DatabaseConfiguration mConfig;
- List<Migration> mAutoMigrations = Arrays.asList(new BuilderTest.EmptyMigration(1, 2));
-
- @Override
- public void init(DatabaseConfiguration configuration) {
- super.init(configuration);
- mConfig = configuration;
- }
-
- @Override
- protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration config) {
- return Mockito.mock(SupportSQLiteOpenHelper.class);
- }
-
- @Override
- protected InvalidationTracker createInvalidationTracker() {
- return Mockito.mock(InvalidationTracker.class);
- }
-
- @Override
- public void clearAllTables() {
- }
-
- @NonNull
- @Override
- public List<Migration> getAutoMigrations(
- @NonNull Map<Class<? extends AutoMigrationSpec>, AutoMigrationSpec> autoMigrationSpecs
- ) {
- return mAutoMigrations;
- }
-}
\ No newline at end of file
diff --git a/room/room-runtime/src/test/java/androidx/room/BuilderTest_TestDatabase_Impl.kt b/room/room-runtime/src/test/java/androidx/room/BuilderTest_TestDatabase_Impl.kt
new file mode 100644
index 0000000..482b0fa
--- /dev/null
+++ b/room/room-runtime/src/test/java/androidx/room/BuilderTest_TestDatabase_Impl.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room
+
+import androidx.room.migration.AutoMigrationSpec
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteOpenHelper
+import org.mockito.kotlin.mock
+
+internal class BuilderTest_TestDatabase_Impl : BuilderTest.TestDatabase() {
+ lateinit var mConfig: DatabaseConfiguration
+ var mAutoMigrations = listOf<Migration>(BuilderTest.EmptyMigration(1, 2))
+ override fun init(configuration: DatabaseConfiguration) {
+ super.init(configuration)
+ mConfig = configuration
+ }
+
+ override fun createOpenHelper(config: DatabaseConfiguration): SupportSQLiteOpenHelper {
+ return mock()
+ }
+
+ override fun createInvalidationTracker(): InvalidationTracker {
+ return mock()
+ }
+
+ override fun clearAllTables() {}
+ override fun getAutoMigrations(
+ autoMigrationSpecs: Map<Class<out AutoMigrationSpec>, AutoMigrationSpec>
+ ): List<Migration> {
+ return mAutoMigrations
+ }
+}
\ No newline at end of file
diff --git a/room/room-runtime/src/test/java/androidx/room/ObservedTableTrackerTest.java b/room/room-runtime/src/test/java/androidx/room/ObservedTableTrackerTest.java
deleted file mode 100644
index 2106fdb..0000000
--- a/room/room-runtime/src/test/java/androidx/room/ObservedTableTrackerTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package androidx.room;
-
-
-import static androidx.room.InvalidationTracker.ObservedTableTracker.ADD;
-import static androidx.room.InvalidationTracker.ObservedTableTracker.NO_OP;
-import static androidx.room.InvalidationTracker.ObservedTableTracker.REMOVE;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.nullValue;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.Arrays;
-
-@RunWith(JUnit4.class)
-public class ObservedTableTrackerTest {
- private static final int TABLE_COUNT = 5;
- private InvalidationTracker.ObservedTableTracker mTracker;
-
- @Before
- public void setup() {
- mTracker = new InvalidationTracker.ObservedTableTracker(TABLE_COUNT);
- }
-
- @Test
- public void basicAdd() {
- mTracker.onAdded(2, 3);
- assertThat(mTracker.getTablesToSync(), is(createResponse(2, ADD, 3, ADD)));
- }
-
- @Test
- public void basicRemove() {
- initState(2, 3);
- mTracker.onRemoved(3);
- assertThat(mTracker.getTablesToSync(), is(createResponse(3, REMOVE)));
- }
-
- @Test
- public void noChange() {
- initState(1, 3);
- mTracker.onAdded(3);
- assertThat(mTracker.getTablesToSync(), is(nullValue()));
- }
-
- @Test
- public void multipleAdditionsDeletions() {
- initState(2, 4);
- mTracker.onAdded(2);
- assertThat(mTracker.getTablesToSync(), is(nullValue()));
- mTracker.onAdded(2, 4);
- assertThat(mTracker.getTablesToSync(), is(nullValue()));
- mTracker.onRemoved(2);
- assertThat(mTracker.getTablesToSync(), is(nullValue()));
- mTracker.onRemoved(2, 4);
- assertThat(mTracker.getTablesToSync(), is(nullValue()));
- mTracker.onAdded(1, 3);
- mTracker.onRemoved(2, 4);
- assertThat(mTracker.getTablesToSync(), is(
- createResponse(1, ADD, 2, REMOVE, 3, ADD, 4, REMOVE)));
- }
-
- private void initState(int... tableIds) {
- mTracker.onAdded(tableIds);
- mTracker.getTablesToSync();
- }
-
- private static int[] createResponse(int... tuples) {
- int[] result = new int[TABLE_COUNT];
- Arrays.fill(result, NO_OP);
- for (int i = 0; i < tuples.length; i += 2) {
- result[tuples[i]] = tuples[i + 1];
- }
- return result;
- }
-}
diff --git a/room/room-runtime/src/test/java/androidx/room/ObservedTableTrackerTest.kt b/room/room-runtime/src/test/java/androidx/room/ObservedTableTrackerTest.kt
new file mode 100644
index 0000000..10ac217
--- /dev/null
+++ b/room/room-runtime/src/test/java/androidx/room/ObservedTableTrackerTest.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.room
+
+import com.google.common.truth.Truth.assertThat
+import java.util.Arrays
+import kotlin.test.assertNull
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ObservedTableTrackerTest {
+ private lateinit var mTracker: InvalidationTracker.ObservedTableTracker
+ @Before
+ fun setup() {
+ mTracker = InvalidationTracker.ObservedTableTracker(TABLE_COUNT)
+ }
+
+ @Test
+ fun basicAdd() {
+ mTracker.onAdded(2, 3)
+ assertThat(
+ mTracker.getTablesToSync()
+ ).isEqualTo(
+ createResponse(
+ 2,
+ InvalidationTracker.ObservedTableTracker.ADD,
+ 3,
+ InvalidationTracker.ObservedTableTracker.ADD
+ )
+ )
+ }
+
+ @Test
+ fun basicRemove() {
+ initState(2, 3)
+ mTracker.onRemoved(3)
+ assertThat(
+ mTracker.getTablesToSync()
+ ).isEqualTo(
+ createResponse(3, InvalidationTracker.ObservedTableTracker.REMOVE)
+ )
+ }
+
+ @Test
+ fun noChange() {
+ initState(1, 3)
+ mTracker.onAdded(3)
+ assertNull(
+ mTracker.getTablesToSync()
+ )
+ }
+
+ @Test
+ fun multipleAdditionsDeletions() {
+ initState(2, 4)
+ mTracker.onAdded(2)
+ assertNull(
+ mTracker.getTablesToSync()
+ )
+ mTracker.onAdded(2, 4)
+ assertNull(
+ mTracker.getTablesToSync()
+ )
+ mTracker.onRemoved(2)
+ assertNull(
+ mTracker.getTablesToSync()
+ )
+ mTracker.onRemoved(2, 4)
+ assertNull(
+ mTracker.getTablesToSync()
+ )
+ mTracker.onAdded(1, 3)
+ mTracker.onRemoved(2, 4)
+ assertThat(
+ mTracker.getTablesToSync()
+ ).isEqualTo(
+ createResponse(
+ 1,
+ InvalidationTracker.ObservedTableTracker.ADD,
+ 2,
+ InvalidationTracker.ObservedTableTracker.REMOVE,
+ 3,
+ InvalidationTracker.ObservedTableTracker.ADD,
+ 4,
+ InvalidationTracker.ObservedTableTracker.REMOVE
+ )
+ )
+ }
+
+ private fun initState(vararg tableIds: Int) {
+ mTracker.onAdded(*tableIds)
+ mTracker.getTablesToSync()
+ }
+
+ companion object {
+ private const val TABLE_COUNT = 5
+ private fun createResponse(vararg tuples: Int): IntArray {
+ val result = IntArray(TABLE_COUNT)
+ Arrays.fill(result, InvalidationTracker.ObservedTableTracker.NO_OP)
+ var i = 0
+ while (i < tuples.size) {
+ result[tuples[i]] = tuples[i + 1]
+ i += 2
+ }
+ return result
+ }
+ }
+}
\ No newline at end of file
diff --git a/room/room-runtime/src/test/java/androidx/room/RoomSQLiteQueryTest.java b/room/room-runtime/src/test/java/androidx/room/RoomSQLiteQueryTest.java
deleted file mode 100644
index 0738a49..0000000
--- a/room/room-runtime/src/test/java/androidx/room/RoomSQLiteQueryTest.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.room;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.sameInstance;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import androidx.sqlite.db.SupportSQLiteProgram;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-@RunWith(JUnit4.class)
-public class RoomSQLiteQueryTest {
- @Before
- public void clear() {
- RoomSQLiteQuery.queryPool.clear();
- }
-
- @Test
- public void acquireBasic() {
- RoomSQLiteQuery query = RoomSQLiteQuery.acquire("abc", 3);
- assertThat(query.getSql(), is("abc"));
- assertThat(query.getArgCount(), is(3));
- assertThat(query.blobBindings.length, is(4));
- assertThat(query.longBindings.length, is(4));
- assertThat(query.stringBindings.length, is(4));
- assertThat(query.doubleBindings.length, is(4));
- }
-
- @Test
- public void acquireSameSizeAgain() {
- RoomSQLiteQuery query = RoomSQLiteQuery.acquire("abc", 3);
- query.release();
- assertThat(RoomSQLiteQuery.acquire("blah", 3), sameInstance(query));
- }
-
- @Test
- public void acquireSameSizeWithoutRelease() {
- RoomSQLiteQuery query = RoomSQLiteQuery.acquire("abc", 3);
- assertThat(RoomSQLiteQuery.acquire("fda", 3), not(sameInstance(query)));
- }
-
- @Test
- public void bindings() {
- RoomSQLiteQuery query = RoomSQLiteQuery.acquire("abc", 6);
- byte[] myBlob = new byte[3];
- long myLong = 3L;
- double myDouble = 7.0;
- String myString = "ss";
- query.bindBlob(1, myBlob);
- query.bindLong(2, myLong);
- query.bindNull(3);
- query.bindDouble(4, myDouble);
- query.bindString(5, myString);
- query.bindNull(6);
- SupportSQLiteProgram program = mock(SupportSQLiteProgram.class);
- query.bindTo(program);
-
- verify(program).bindBlob(1, myBlob);
- verify(program).bindLong(2, myLong);
- verify(program).bindNull(3);
- verify(program).bindDouble(4, myDouble);
- verify(program).bindString(5, myString);
- verify(program).bindNull(6);
- }
-
- @Test
- public void dontKeepSameSizeTwice() {
- RoomSQLiteQuery query1 = RoomSQLiteQuery.acquire("abc", 3);
- RoomSQLiteQuery query2 = RoomSQLiteQuery.acquire("zx", 3);
- RoomSQLiteQuery query3 = RoomSQLiteQuery.acquire("qw", 0);
-
- query1.release();
- query2.release();
- assertThat(RoomSQLiteQuery.queryPool.size(), is(1));
-
- query3.release();
- assertThat(RoomSQLiteQuery.queryPool.size(), is(2));
- }
-
- @Test
- public void returnExistingForSmallerSize() {
- RoomSQLiteQuery query = RoomSQLiteQuery.acquire("abc", 3);
- query.release();
- assertThat(RoomSQLiteQuery.acquire("dsa", 2), sameInstance(query));
- }
-
- @Test
- public void returnNewForBigger() {
- RoomSQLiteQuery query = RoomSQLiteQuery.acquire("abc", 3);
- query.release();
- assertThat(RoomSQLiteQuery.acquire("dsa", 4), not(sameInstance(query)));
- }
-
- @Test
- public void pruneCache() {
- for (int i = 0; i < RoomSQLiteQuery.POOL_LIMIT; i++) {
- RoomSQLiteQuery.acquire("dsdsa", i).release();
- }
- pruneCacheTest();
- }
-
- @Test
- public void pruneCacheReverseInsertion() {
- List<RoomSQLiteQuery> queries = new ArrayList<>();
- for (int i = RoomSQLiteQuery.POOL_LIMIT - 1; i >= 0; i--) {
- queries.add(RoomSQLiteQuery.acquire("dsdsa", i));
- }
- for (RoomSQLiteQuery query : queries) {
- query.release();
- }
- pruneCacheTest();
- }
-
- private void pruneCacheTest() {
- assertThat(RoomSQLiteQuery.queryPool.size(), is(RoomSQLiteQuery.POOL_LIMIT));
- RoomSQLiteQuery.acquire("dsadsa", RoomSQLiteQuery.POOL_LIMIT + 1).release();
- assertThat(RoomSQLiteQuery.queryPool.size(), is(RoomSQLiteQuery.DESIRED_POOL_SIZE));
- Iterator<RoomSQLiteQuery> itr = RoomSQLiteQuery.queryPool.values().iterator();
- for (int i = 0; i < RoomSQLiteQuery.DESIRED_POOL_SIZE; i++) {
- assertThat(itr.next().getCapacity(), is(i));
- }
- }
-}
diff --git a/room/room-runtime/src/test/java/androidx/room/RoomSQLiteQueryTest.kt b/room/room-runtime/src/test/java/androidx/room/RoomSQLiteQueryTest.kt
new file mode 100644
index 0000000..669b7f2
--- /dev/null
+++ b/room/room-runtime/src/test/java/androidx/room/RoomSQLiteQueryTest.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room
+
+import androidx.room.RoomSQLiteQuery.Companion.acquire
+import androidx.sqlite.db.SupportSQLiteProgram
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+
+@RunWith(JUnit4::class)
+class RoomSQLiteQueryTest {
+ @Before
+ fun clear() {
+ RoomSQLiteQuery.queryPool.clear()
+ }
+
+ @Test
+ fun acquireBasic() {
+ val query = acquire("abc", 3)
+ assertThat(query.sql).isEqualTo("abc")
+ assertThat(query.argCount).isEqualTo(3)
+ assertThat(query.blobBindings.size).isEqualTo(4)
+ assertThat(query.longBindings.size).isEqualTo(4)
+ assertThat(query.stringBindings.size).isEqualTo(4)
+ assertThat(query.doubleBindings.size).isEqualTo(4)
+ }
+
+ @Test
+ fun acquireSameSizeAgain() {
+ val query = acquire("abc", 3)
+ query.release()
+ assertThat(acquire("blah", 3)).isSameInstanceAs(query)
+ }
+
+ @Test
+ fun acquireSameSizeWithoutRelease() {
+ val query = acquire("abc", 3)
+ assertThat(
+ acquire("fda", 3)
+ ).isNotSameInstanceAs(query)
+ }
+
+ @Test
+ fun bindings() {
+ val query = acquire("abc", 6)
+ val myBlob = ByteArray(3)
+ val myLong = 3L
+ val myDouble = 7.0
+ val myString = "ss"
+ query.bindBlob(1, myBlob)
+ query.bindLong(2, myLong)
+ query.bindNull(3)
+ query.bindDouble(4, myDouble)
+ query.bindString(5, myString)
+ query.bindNull(6)
+ val program: SupportSQLiteProgram = mock()
+ query.bindTo(program)
+ verify(program).bindBlob(1, myBlob)
+ verify(program).bindLong(2, myLong)
+ verify(program).bindNull(3)
+ verify(program).bindDouble(4, myDouble)
+ verify(program).bindString(5, myString)
+ verify(program).bindNull(6)
+ }
+
+ @Test
+ fun dontKeepSameSizeTwice() {
+ val query1 = acquire("abc", 3)
+ val query2 = acquire("zx", 3)
+ val query3 = acquire("qw", 0)
+ query1.release()
+ query2.release()
+ assertThat(RoomSQLiteQuery.queryPool.size).isEqualTo(1)
+ query3.release()
+ assertThat(RoomSQLiteQuery.queryPool.size).isEqualTo(2)
+ }
+
+ @Test
+ fun returnExistingForSmallerSize() {
+ val query = acquire("abc", 3)
+ query.release()
+ assertThat(acquire("dsa", 2)).isSameInstanceAs(query)
+ }
+
+ @Test
+ fun returnNewForBigger() {
+ val query = acquire("abc", 3)
+ query.release()
+ assertThat(
+ acquire("dsa", 4)
+ ).isNotSameInstanceAs(query)
+ }
+
+ @Test
+ fun pruneCache() {
+ for (i in 0 until RoomSQLiteQuery.POOL_LIMIT) {
+ acquire("dsdsa", i).release()
+ }
+ pruneCacheTest()
+ }
+
+ @Test
+ fun pruneCacheReverseInsertion() {
+ val queries: MutableList<RoomSQLiteQuery> = ArrayList()
+ for (i in RoomSQLiteQuery.POOL_LIMIT - 1 downTo 0) {
+ queries.add(acquire("dsdsa", i))
+ }
+ for (query in queries) {
+ query.release()
+ }
+ pruneCacheTest()
+ }
+
+ private fun pruneCacheTest() {
+ assertThat(
+ RoomSQLiteQuery.queryPool.size
+ ).isEqualTo(RoomSQLiteQuery.POOL_LIMIT)
+ acquire("dsadsa", RoomSQLiteQuery.POOL_LIMIT + 1).release()
+ assertThat(
+ RoomSQLiteQuery.queryPool.size
+ ).isEqualTo(RoomSQLiteQuery.DESIRED_POOL_SIZE)
+ val itr: Iterator<RoomSQLiteQuery> = RoomSQLiteQuery.queryPool.values.iterator()
+ for (i in 0 until RoomSQLiteQuery.DESIRED_POOL_SIZE) {
+ assertThat(itr.next().capacity).isEqualTo(i)
+ }
+ }
+}
\ No newline at end of file
diff --git a/room/room-runtime/src/test/java/androidx/room/SharedSQLiteStatementTest.java b/room/room-runtime/src/test/java/androidx/room/SharedSQLiteStatementTest.java
deleted file mode 100644
index dde3a3a..0000000
--- a/room/room-runtime/src/test/java/androidx/room/SharedSQLiteStatementTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.room;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import androidx.sqlite.db.SupportSQLiteStatement;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
-
-@RunWith(JUnit4.class)
-public class SharedSQLiteStatementTest {
- private SharedSQLiteStatement mSharedStmt;
- RoomDatabase mDb;
- @Before
- public void init() {
- mDb = mock(RoomDatabase.class);
- when(mDb.compileStatement(anyString())).thenAnswer(new Answer<SupportSQLiteStatement>() {
-
- @Override
- public SupportSQLiteStatement answer(InvocationOnMock invocation) throws Throwable {
- return mock(SupportSQLiteStatement.class);
- }
- });
- when(mDb.getInvalidationTracker()).thenReturn(mock(InvalidationTracker.class));
- mSharedStmt = new SharedSQLiteStatement(mDb) {
- @Override
- protected String createQuery() {
- return "foo";
- }
- };
- }
-
- @Test
- public void checkMainThread() {
- mSharedStmt.acquire();
- verify(mDb).assertNotMainThread();
- }
-
- @Test
- public void basic() {
- assertThat(mSharedStmt.acquire(), notNullValue());
- }
-
- @Test
- public void getTwiceWithoutReleasing() {
- SupportSQLiteStatement stmt1 = mSharedStmt.acquire();
- SupportSQLiteStatement stmt2 = mSharedStmt.acquire();
- assertThat(stmt1, notNullValue());
- assertThat(stmt2, notNullValue());
- assertThat(stmt1, is(not(stmt2)));
- }
-
- @Test
- public void getTwiceWithReleasing() {
- SupportSQLiteStatement stmt1 = mSharedStmt.acquire();
- mSharedStmt.release(stmt1);
- SupportSQLiteStatement stmt2 = mSharedStmt.acquire();
- assertThat(stmt1, notNullValue());
- assertThat(stmt1, is(stmt2));
- }
-
- @Test
- public void getFromAnotherThreadWhileHolding() throws ExecutionException, InterruptedException {
- SupportSQLiteStatement stmt1 = mSharedStmt.acquire();
- FutureTask<SupportSQLiteStatement> task = new FutureTask<>(
- new Callable<SupportSQLiteStatement>() {
- @Override
- public SupportSQLiteStatement call() throws Exception {
- return mSharedStmt.acquire();
- }
- });
- new Thread(task).run();
- SupportSQLiteStatement stmt2 = task.get();
- assertThat(stmt1, notNullValue());
- assertThat(stmt2, notNullValue());
- assertThat(stmt1, is(not(stmt2)));
- }
-
- @Test
- public void getFromAnotherThreadAfterReleasing() throws ExecutionException,
- InterruptedException {
- SupportSQLiteStatement stmt1 = mSharedStmt.acquire();
- mSharedStmt.release(stmt1);
- FutureTask<SupportSQLiteStatement> task = new FutureTask<>(
- new Callable<SupportSQLiteStatement>() {
- @Override
- public SupportSQLiteStatement call() throws Exception {
- return mSharedStmt.acquire();
- }
- });
- new Thread(task).run();
- SupportSQLiteStatement stmt2 = task.get();
- assertThat(stmt1, notNullValue());
- assertThat(stmt1, is(stmt2));
- }
-}
diff --git a/room/room-runtime/src/test/java/androidx/room/SharedSQLiteStatementTest.kt b/room/room-runtime/src/test/java/androidx/room/SharedSQLiteStatementTest.kt
new file mode 100644
index 0000000..c9da445
--- /dev/null
+++ b/room/room-runtime/src/test/java/androidx/room/SharedSQLiteStatementTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.room
+
+import androidx.sqlite.db.SupportSQLiteStatement
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.FutureTask
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@RunWith(JUnit4::class)
+class SharedSQLiteStatementTest {
+ private lateinit var mSharedStmt: SharedSQLiteStatement
+ lateinit var mDb: RoomDatabase
+ @Before
+ fun init() {
+ val mdata: RoomDatabase = mock()
+ whenever(mdata.compileStatement(anyOrNull())).thenAnswer {
+ mock<SupportSQLiteStatement>()
+ }
+ whenever(mdata.invalidationTracker).thenReturn(mock())
+ mDb = mdata
+ mSharedStmt = object : SharedSQLiteStatement(mdata) {
+ override fun createQuery(): String {
+ return "foo"
+ }
+ }
+ }
+
+ @Test
+ fun checkMainThread() {
+ mSharedStmt.acquire()
+ verify(mDb).assertNotMainThread()
+ }
+
+ @Test
+ fun basic() {
+ assertThat(mSharedStmt.acquire()).isNotNull()
+ }
+
+ @Test
+ fun twiceWithoutReleasing() {
+ val stmt1 = mSharedStmt.acquire()
+ val stmt2 = mSharedStmt.acquire()
+ assertThat(stmt1).isNotNull()
+ assertThat(stmt2).isNotNull()
+ assertThat(stmt1).isNotEqualTo(stmt2)
+ }
+
+ @Test
+ fun twiceWithReleasing() {
+ val stmt1 = mSharedStmt.acquire()
+ mSharedStmt.release(stmt1)
+ val stmt2 = mSharedStmt.acquire()
+ assertThat(stmt1).isNotNull()
+ assertThat(stmt1).isEqualTo(stmt2)
+ }
+
+ @Test
+ fun fromAnotherThreadWhileHolding() {
+ val stmt1 = mSharedStmt.acquire()
+ val task = FutureTask { mSharedStmt.acquire() }
+ Thread(task).start()
+ val stmt2 = task.get()
+ assertThat(stmt1).isNotNull()
+ assertThat(stmt2).isNotNull()
+ assertThat(stmt1).isNotEqualTo(stmt2)
+ }
+
+ @Test
+ fun fromAnotherThreadAfterReleasing() {
+ val stmt1 = mSharedStmt.acquire()
+ mSharedStmt.release(stmt1)
+ val task = FutureTask { mSharedStmt.acquire() }
+ Thread(task).start()
+ val stmt2 = task.get()
+ assertThat(stmt1).isNotNull()
+ assertThat(stmt1).isEqualTo(stmt2)
+ }
+}
\ No newline at end of file
diff --git a/samples/AndroidXDemos/lint-baseline.xml b/samples/AndroidXDemos/lint-baseline.xml
index 66b57c7..6748694 100644
--- a/samples/AndroidXDemos/lint-baseline.xml
+++ b/samples/AndroidXDemos/lint-baseline.xml
@@ -215,7 +215,7 @@
id="NewApi"
message="`<class>` requires API level 24 (current min is 14)"
errorLine1=" class="com.example.androidx.drawable.MyDrawable""
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/drawable/my_drawable.xml"/>
</issue>
@@ -653,6 +653,105 @@
<issue
id="UnknownNullness"
message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" public void onCreate(Bundle savedInstanceState) {"
+ errorLine2=" ~~~~~~">
+ <location
+ file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" protected List<Map<String, Object>> getData(String prefix) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" protected List<Map<String, Object>> getData(String prefix) {"
+ errorLine2=" ~~~~~~">
+ <location
+ file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" protected Intent activityIntent(String pkg, String componentName) {"
+ errorLine2=" ~~~~~~">
+ <location
+ file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" protected Intent activityIntent(String pkg, String componentName) {"
+ errorLine2=" ~~~~~~">
+ <location
+ file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" protected Intent activityIntent(String pkg, String componentName) {"
+ errorLine2=" ~~~~~~">
+ <location
+ file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" protected Intent browseIntent(String path) {"
+ errorLine2=" ~~~~~~">
+ <location
+ file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" protected Intent browseIntent(String path) {"
+ errorLine2=" ~~~~~~">
+ <location
+ file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" protected void addItem(List<Map<String, Object>> data, String name, Intent intent) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" protected void addItem(List<Map<String, Object>> data, String name, Intent intent) {"
+ errorLine2=" ~~~~~~">
+ <location
+ file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" protected void addItem(List<Map<String, Object>> data, String name, Intent intent) {"
+ errorLine2=" ~~~~~~">
+ <location
+ file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
errorLine1=" protected void onCreate(Bundle savedInstanceState) {"
errorLine2=" ~~~~~~">
<location
@@ -2984,105 +3083,6 @@
<issue
id="UnknownNullness"
message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public void onCreate(Bundle savedInstanceState) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" protected List<Map<String, Object>> getData(String prefix) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" protected List<Map<String, Object>> getData(String prefix) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" protected Intent activityIntent(String pkg, String componentName) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" protected Intent activityIntent(String pkg, String componentName) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" protected Intent activityIntent(String pkg, String componentName) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" protected Intent browseIntent(String path) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" protected Intent browseIntent(String path) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" protected void addItem(List<Map<String, Object>> data, String name, Intent intent) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" protected void addItem(List<Map<String, Object>> data, String name, Intent intent) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" protected void addItem(List<Map<String, Object>> data, String name, Intent intent) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/com/example/androidx/AndroidXDemos.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
errorLine1=" public void onBind(ItemTouchViewHolder viewHolder) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
diff --git a/samples/SupportPreferenceDemos/lint-baseline.xml b/samples/SupportPreferenceDemos/lint-baseline.xml
index a2a2fdc..a3353c4 100644
--- a/samples/SupportPreferenceDemos/lint-baseline.xml
+++ b/samples/SupportPreferenceDemos/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<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="MissingTvBanner"
diff --git a/samples/SupportSliceDemos/lint-baseline.xml b/samples/SupportSliceDemos/lint-baseline.xml
index 128542c..1a9fe29 100644
--- a/samples/SupportSliceDemos/lint-baseline.xml
+++ b/samples/SupportSliceDemos/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
<issue
id="UnknownNullness"
diff --git a/samples/SupportWearDemos/lint-baseline.xml b/samples/SupportWearDemos/lint-baseline.xml
index 66e9a6c..cfbc3a4 100644
--- a/samples/SupportWearDemos/lint-baseline.xml
+++ b/samples/SupportWearDemos/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
<issue
id="UnknownNullness"
diff --git a/security/security-crypto/lint-baseline.xml b/security/security-crypto/lint-baseline.xml
index b611da6..e23c350 100644
--- a/security/security-crypto/lint-baseline.xml
+++ b/security/security-crypto/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
<issue
id="BanSynchronizedMethods"
diff --git a/settings.gradle b/settings.gradle
index 8a420cb..130475d 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -598,6 +598,7 @@
includeProject(":core:uwb:uwb-rxjava3", [BuildType.MAIN])
includeProject(":credentials:credentials", [BuildType.MAIN])
includeProject(":credentials:credentials-play-services-auth", [BuildType.MAIN])
+includeProject(":credentials:credentials-provider", [BuildType.MAIN])
includeProject(":cursoradapter:cursoradapter", [BuildType.MAIN])
includeProject(":customview:customview", [BuildType.MAIN])
includeProject(":customview:customview-poolingcontainer", [BuildType.MAIN, BuildType.COMPOSE])
@@ -848,7 +849,7 @@
includeProject(":test:ext:junit-gtest", [BuildType.NATIVE])
includeProject(":test:integration-tests:junit-gtest-test", [BuildType.NATIVE])
includeProject(":test:screenshot:screenshot")
-includeProject(":test:screenshot:screenshot-paparazzi", [BuildType.MAIN, BuildType.COMPOSE])
+includeProject(":test:screenshot:screenshot-layoutlib", [BuildType.MAIN, BuildType.COMPOSE])
includeProject(":test:screenshot:screenshot-proto")
includeProject(":test:uiautomator:uiautomator", [BuildType.MAIN])
includeProject(":test:uiautomator:integration-tests:testapp", [BuildType.MAIN])
diff --git a/slice/slice-builders/lint-baseline.xml b/slice/slice-builders/lint-baseline.xml
index c8166a0..0ff48cb 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 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
<issue
id="WrongConstant"
diff --git a/slice/slice-core/lint-baseline.xml b/slice/slice-core/lint-baseline.xml
index 90d930b..d036494 100644
--- a/slice/slice-core/lint-baseline.xml
+++ b/slice/slice-core/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
<issue
id="BanUncheckedReflection"
diff --git a/slice/slice-view/lint-baseline.xml b/slice/slice-view/lint-baseline.xml
index 2a146f2..d5a0743 100644
--- a/slice/slice-view/lint-baseline.xml
+++ b/slice/slice-view/lint-baseline.xml
@@ -74,60 +74,6 @@
</issue>
<issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="abc_slice_duration_min" formatted="false" msgid="7664017844210142826">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr-rCA/strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="abc_slice_duration_min" formatted="false" msgid="7664017844210142826">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr/strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="abc_slice_duration_years" formatted="false" msgid="2628491538787454021">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr-rCA/strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="abc_slice_duration_years" formatted="false" msgid="2628491538787454021">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr/strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="abc_slice_duration_days" formatted="false" msgid="8356547162075064530">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr-rCA/strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="abc_slice_duration_days" formatted="false" msgid="8356547162075064530">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr/strings.xml"/>
- </issue>
-
- <issue
id="UnknownNullness"
message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
errorLine1=" public ActionRow(Context context, boolean fullActions) {"
diff --git a/sqlite/integration-tests/inspection-room-testapp/lint-baseline.xml b/sqlite/integration-tests/inspection-room-testapp/lint-baseline.xml
index 719e8ec..ce89072 100644
--- a/sqlite/integration-tests/inspection-room-testapp/lint-baseline.xml
+++ b/sqlite/integration-tests/inspection-room-testapp/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<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="MissingTestSizeAnnotation"
diff --git a/sqlite/sqlite/lint-baseline.xml b/sqlite/sqlite/lint-baseline.xml
deleted file mode 100644
index 58c8b41..0000000
--- a/sqlite/sqlite/lint-baseline.xml
+++ /dev/null
@@ -1,157 +0,0 @@
-<?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="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public static SupportSQLiteQueryBuilder builder(String tableName) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public static SupportSQLiteQueryBuilder builder(String tableName) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder distinct() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder columns(String[] columns) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder columns(String[] columns) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder selection(String selection, Object[] bindArgs) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder selection(String selection, Object[] bindArgs) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder selection(String selection, Object[] bindArgs) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder groupBy(String groupBy) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder groupBy(String groupBy) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder having(String having) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder having(String having) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder orderBy(String orderBy) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder orderBy(String orderBy) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder limit(String limit) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQueryBuilder limit(String limit) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
- errorLine1=" public SupportSQLiteQuery create() {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/sqlite/db/SupportSQLiteQueryBuilder.java"/>
- </issue>
-
-</issues>
diff --git a/test/screenshot/screenshot-paparazzi/build.gradle b/test/screenshot/screenshot-layoutlib/build.gradle
similarity index 100%
rename from test/screenshot/screenshot-paparazzi/build.gradle
rename to test/screenshot/screenshot-layoutlib/build.gradle
diff --git a/test/screenshot/screenshot-paparazzi/src/main/kotlin/androidx/test/screenshot/paparazzi/AndroidXPaparazziTestRule.kt b/test/screenshot/screenshot-layoutlib/src/main/kotlin/androidx/test/screenshot/layoutlib/AndroidXLayoutlibTestRule.kt
similarity index 91%
rename from test/screenshot/screenshot-paparazzi/src/main/kotlin/androidx/test/screenshot/paparazzi/AndroidXPaparazziTestRule.kt
rename to test/screenshot/screenshot-layoutlib/src/main/kotlin/androidx/test/screenshot/layoutlib/AndroidXLayoutlibTestRule.kt
index aa727e0..3ae6ebf 100644
--- a/test/screenshot/screenshot-paparazzi/src/main/kotlin/androidx/test/screenshot/paparazzi/AndroidXPaparazziTestRule.kt
+++ b/test/screenshot/screenshot-layoutlib/src/main/kotlin/androidx/test/screenshot/layoutlib/AndroidXLayoutlibTestRule.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.test.screenshot.paparazzi
+package androidx.test.screenshot.layoutlib
import app.cash.paparazzi.DeviceConfig
import app.cash.paparazzi.Environment
@@ -25,7 +25,7 @@
/**
* Creates a [Paparazzi] test rule configured from system properties for AndroidX tests.
*/
-fun AndroidXPaparazziTestRule(
+fun AndroidXLayoutlibTestRule(
deviceConfig: DeviceConfig = DeviceConfig.NEXUS_5.copy(softButtons = false),
theme: String = "android:Theme.Material.NoActionBar.Fullscreen",
renderingMode: RenderingMode = RenderingMode.NORMAL,
@@ -51,13 +51,13 @@
)
/** Package name used for resolving system properties */
-private const val PACKAGE_NAME = "androidx.test.screenshot.paparazzi"
+private const val PACKAGE_NAME = "androidx.test.screenshot.layoutlib"
/** Read a system property with [PACKAGE_NAME] prefix, throwing an exception if missing */
private fun systemProperty(name: String) =
requireNotNull(System.getProperty("$PACKAGE_NAME.$name")) {
"System property $PACKAGE_NAME.$name is not set. You may need to apply " +
- "AndroidXPaparazziPlugin to your Gradle build."
+ "AndroidXLayoutlibPlugin to your Gradle build."
}
/** Little helper to convert string path to [File] to improve readability */
diff --git a/test/screenshot/screenshot-paparazzi/src/main/kotlin/androidx/test/screenshot/paparazzi/GoldenVerifier.kt b/test/screenshot/screenshot-layoutlib/src/main/kotlin/androidx/test/screenshot/layoutlib/GoldenVerifier.kt
similarity index 99%
rename from test/screenshot/screenshot-paparazzi/src/main/kotlin/androidx/test/screenshot/paparazzi/GoldenVerifier.kt
rename to test/screenshot/screenshot-layoutlib/src/main/kotlin/androidx/test/screenshot/layoutlib/GoldenVerifier.kt
index 1e58c90..f58a421 100644
--- a/test/screenshot/screenshot-paparazzi/src/main/kotlin/androidx/test/screenshot/paparazzi/GoldenVerifier.kt
+++ b/test/screenshot/screenshot-layoutlib/src/main/kotlin/androidx/test/screenshot/layoutlib/GoldenVerifier.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.test.screenshot.paparazzi
+package androidx.test.screenshot.layoutlib
import androidx.test.screenshot.proto.ScreenshotResultProto.ScreenshotResult
import androidx.test.screenshot.proto.ScreenshotResultProto.ScreenshotResult.Status
diff --git a/test/screenshot/screenshot-paparazzi/src/main/kotlin/androidx/test/screenshot/paparazzi/ImageDiffer.kt b/test/screenshot/screenshot-layoutlib/src/main/kotlin/androidx/test/screenshot/layoutlib/ImageDiffer.kt
similarity index 97%
rename from test/screenshot/screenshot-paparazzi/src/main/kotlin/androidx/test/screenshot/paparazzi/ImageDiffer.kt
rename to test/screenshot/screenshot-layoutlib/src/main/kotlin/androidx/test/screenshot/layoutlib/ImageDiffer.kt
index 72e9e99..d82adce 100644
--- a/test/screenshot/screenshot-paparazzi/src/main/kotlin/androidx/test/screenshot/paparazzi/ImageDiffer.kt
+++ b/test/screenshot/screenshot-layoutlib/src/main/kotlin/androidx/test/screenshot/layoutlib/ImageDiffer.kt
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package androidx.test.screenshot.paparazzi
+package androidx.test.screenshot.layoutlib
-import androidx.test.screenshot.paparazzi.ImageDiffer.DiffResult.Similar
+import androidx.test.screenshot.layoutlib.ImageDiffer.DiffResult.Similar
import java.awt.image.BufferedImage
/**
diff --git a/test/screenshot/screenshot-paparazzi/src/test/kotlin/androidx/test/screenshot/paparazzi/GoldenVerifierTest.kt b/test/screenshot/screenshot-layoutlib/src/test/kotlin/androidx/test/screenshot/paparazzi/GoldenVerifierTest.kt
similarity index 98%
rename from test/screenshot/screenshot-paparazzi/src/test/kotlin/androidx/test/screenshot/paparazzi/GoldenVerifierTest.kt
rename to test/screenshot/screenshot-layoutlib/src/test/kotlin/androidx/test/screenshot/paparazzi/GoldenVerifierTest.kt
index cbaa845..1200d53 100644
--- a/test/screenshot/screenshot-paparazzi/src/test/kotlin/androidx/test/screenshot/paparazzi/GoldenVerifierTest.kt
+++ b/test/screenshot/screenshot-layoutlib/src/test/kotlin/androidx/test/screenshot/paparazzi/GoldenVerifierTest.kt
@@ -16,6 +16,8 @@
package androidx.test.screenshot.paparazzi
+import androidx.test.screenshot.layoutlib.GoldenVerifier
+import androidx.test.screenshot.layoutlib.ImageDiffer
import androidx.test.screenshot.proto.ScreenshotResultProto.ScreenshotResult
import androidx.test.screenshot.proto.ScreenshotResultProto.ScreenshotResult.Status
import app.cash.paparazzi.Snapshot
diff --git a/test/screenshot/screenshot-paparazzi/src/test/kotlin/androidx/test/screenshot/paparazzi/ImageDifferTest.kt b/test/screenshot/screenshot-layoutlib/src/test/kotlin/androidx/test/screenshot/paparazzi/ImageDifferTest.kt
similarity index 89%
rename from test/screenshot/screenshot-paparazzi/src/test/kotlin/androidx/test/screenshot/paparazzi/ImageDifferTest.kt
rename to test/screenshot/screenshot-layoutlib/src/test/kotlin/androidx/test/screenshot/paparazzi/ImageDifferTest.kt
index 341d454..092a5c9 100644
--- a/test/screenshot/screenshot-paparazzi/src/test/kotlin/androidx/test/screenshot/paparazzi/ImageDifferTest.kt
+++ b/test/screenshot/screenshot-layoutlib/src/test/kotlin/androidx/test/screenshot/paparazzi/ImageDifferTest.kt
@@ -16,9 +16,9 @@
package androidx.test.screenshot.paparazzi
-import androidx.test.screenshot.paparazzi.ImageDiffer.DiffResult.Different
-import androidx.test.screenshot.paparazzi.ImageDiffer.DiffResult.Similar
-import androidx.test.screenshot.paparazzi.ImageDiffer.PixelPerfect
+import androidx.test.screenshot.layoutlib.ImageDiffer.DiffResult.Different
+import androidx.test.screenshot.layoutlib.ImageDiffer.DiffResult.Similar
+import androidx.test.screenshot.layoutlib.ImageDiffer.PixelPerfect
import javax.imageio.ImageIO
import kotlin.test.Test
import kotlin.test.assertEquals
diff --git a/test/screenshot/screenshot-paparazzi/src/test/resources/androidx/test/screenshot/paparazzi/PixelPerfect_diff.png b/test/screenshot/screenshot-layoutlib/src/test/resources/androidx/test/screenshot/paparazzi/PixelPerfect_diff.png
similarity index 100%
rename from test/screenshot/screenshot-paparazzi/src/test/resources/androidx/test/screenshot/paparazzi/PixelPerfect_diff.png
rename to test/screenshot/screenshot-layoutlib/src/test/resources/androidx/test/screenshot/paparazzi/PixelPerfect_diff.png
Binary files differ
diff --git a/test/screenshot/screenshot-paparazzi/src/test/resources/androidx/test/screenshot/paparazzi/circle.png b/test/screenshot/screenshot-layoutlib/src/test/resources/androidx/test/screenshot/paparazzi/circle.png
similarity index 100%
rename from test/screenshot/screenshot-paparazzi/src/test/resources/androidx/test/screenshot/paparazzi/circle.png
rename to test/screenshot/screenshot-layoutlib/src/test/resources/androidx/test/screenshot/paparazzi/circle.png
Binary files differ
diff --git a/test/screenshot/screenshot-paparazzi/src/test/resources/androidx/test/screenshot/paparazzi/horizontal_rectangle.png b/test/screenshot/screenshot-layoutlib/src/test/resources/androidx/test/screenshot/paparazzi/horizontal_rectangle.png
similarity index 100%
rename from test/screenshot/screenshot-paparazzi/src/test/resources/androidx/test/screenshot/paparazzi/horizontal_rectangle.png
rename to test/screenshot/screenshot-layoutlib/src/test/resources/androidx/test/screenshot/paparazzi/horizontal_rectangle.png
Binary files differ
diff --git a/test/screenshot/screenshot-paparazzi/src/test/resources/androidx/test/screenshot/paparazzi/star.png b/test/screenshot/screenshot-layoutlib/src/test/resources/androidx/test/screenshot/paparazzi/star.png
similarity index 100%
rename from test/screenshot/screenshot-paparazzi/src/test/resources/androidx/test/screenshot/paparazzi/star.png
rename to test/screenshot/screenshot-layoutlib/src/test/resources/androidx/test/screenshot/paparazzi/star.png
Binary files differ
diff --git a/test/screenshot/screenshot-paparazzi/src/test/resources/androidx/test/screenshot/paparazzi/vertical_rectangle.png b/test/screenshot/screenshot-layoutlib/src/test/resources/androidx/test/screenshot/paparazzi/vertical_rectangle.png
similarity index 100%
rename from test/screenshot/screenshot-paparazzi/src/test/resources/androidx/test/screenshot/paparazzi/vertical_rectangle.png
rename to test/screenshot/screenshot-layoutlib/src/test/resources/androidx/test/screenshot/paparazzi/vertical_rectangle.png
Binary files differ
diff --git a/testutils/testutils-runtime/lint-baseline.xml b/testutils/testutils-runtime/lint-baseline.xml
index 2d2a7d3..8f6f992 100644
--- a/testutils/testutils-runtime/lint-baseline.xml
+++ b/testutils/testutils-runtime/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
<issue
id="BanUncheckedReflection"
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridPrefetcherTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridPrefetcherTest.kt
index a2d095d..914a8d7 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridPrefetcherTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridPrefetcherTest.kt
@@ -32,6 +32,7 @@
import androidx.compose.ui.unit.dp
import androidx.test.filters.LargeTest
import androidx.tv.foundation.lazy.AutoTestFrameClock
+import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
@@ -59,7 +60,7 @@
@Test
fun notPrefetchingForwardInitially() {
- composeList()
+ composeGrid()
rule.onNodeWithTag("4")
.assertDoesNotExist()
@@ -67,7 +68,7 @@
@Test
fun notPrefetchingBackwardInitially() {
- composeList(firstItem = 4)
+ composeGrid(firstItem = 4)
rule.onNodeWithTag("0")
.assertDoesNotExist()
@@ -75,7 +76,7 @@
@Test
fun prefetchingForwardAfterSmallScroll() {
- composeList()
+ composeGrid()
rule.runOnIdle {
runBlocking {
@@ -95,7 +96,7 @@
@Test
fun prefetchingBackwardAfterSmallScroll() {
- composeList(firstItem = 4, itemOffset = 10)
+ composeGrid(firstItem = 4, itemOffset = 10)
rule.runOnIdle {
runBlocking {
@@ -115,7 +116,7 @@
@Test
fun prefetchingForwardAndBackward() {
- composeList(firstItem = 2)
+ composeGrid(firstItem = 2)
rule.runOnIdle {
runBlocking {
@@ -151,7 +152,7 @@
@Test
fun prefetchingForwardTwice() {
- composeList()
+ composeGrid()
rule.runOnIdle {
runBlocking {
@@ -180,7 +181,7 @@
@Test
fun prefetchingBackwardTwice() {
- composeList(firstItem = 8)
+ composeGrid(firstItem = 8)
rule.runOnIdle {
runBlocking {
@@ -211,7 +212,7 @@
@Test
fun prefetchingForwardAndBackwardReverseLayout() {
- composeList(firstItem = 2, reverseLayout = true)
+ composeGrid(firstItem = 2, reverseLayout = true)
rule.runOnIdle {
runBlocking {
@@ -252,7 +253,7 @@
@Test
fun prefetchingForwardAndBackwardWithContentPadding() {
val halfItemSize = itemsSizeDp / 2f
- composeList(
+ composeGrid(
firstItem = 4,
itemOffset = 5,
contentPadding = PaddingValues(mainAxis = halfItemSize)
@@ -343,6 +344,40 @@
rule.runOnIdle { }
}
+ @Test
+ fun scrollingByListSizeCancelsPreviousPrefetch() {
+ composeGrid()
+
+ // now we have items 0-3 visible
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ // this will move the viewport so items 2-5 are visible
+ // and schedule a prefetching for 6-7
+ state.scrollBy(itemsSizePx.toFloat())
+
+ // move viewport by screen size to items 8-11, so item 6 is just behind
+ // the first visible item
+ state.scrollBy(itemsSizePx * 3f)
+
+ // move scroll further to items 10-13, so item 6 is reused
+ state.scrollBy(itemsSizePx.toFloat())
+ }
+ }
+
+ waitForPrefetch(13)
+
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ // scroll again to ensure item 6 was dropped
+ state.scrollBy(itemsSizePx * 100f)
+ }
+ }
+
+ rule.runOnIdle {
+ assertThat(activeNodes).doesNotContain(6)
+ }
+ }
+
private fun waitForPrefetch(index: Int) {
rule.waitUntil {
activeNodes.contains(index) && activeMeasuredNodes.contains(index)
@@ -352,7 +387,7 @@
private val activeNodes = mutableSetOf<Int>()
private val activeMeasuredNodes = mutableSetOf<Int>()
- private fun composeList(
+ private fun composeGrid(
firstItem: Int = 0,
itemOffset: Int = 0,
reverseLayout: Boolean = false,
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListPrefetcherTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListPrefetcherTest.kt
index 14401a4..13f31cf 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListPrefetcherTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListPrefetcherTest.kt
@@ -32,6 +32,7 @@
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.unit.dp
import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
@@ -326,6 +327,40 @@
rule.runOnIdle { }
}
+ @Test
+ fun scrollingByListSizeCancelsPreviousPrefetch() {
+ composeList()
+
+ // now we have items 0-1 visible
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ // this will move the viewport so items 1-2 are visible
+ // and schedule a prefetching for 3
+ state.scrollBy(itemsSizePx.toFloat())
+
+ // move viewport by screen size to items 4-5, so item 3 is just behind
+ // the first visible item
+ state.scrollBy(itemsSizePx * 3f)
+
+ // move scroll further to items 5-6, so item 3 is reused
+ state.scrollBy(itemsSizePx.toFloat())
+ }
+ }
+
+ waitForPrefetch(7)
+
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ // scroll again to ensure item 3 was dropped
+ state.scrollBy(itemsSizePx * 100f)
+ }
+ }
+
+ rule.runOnIdle {
+ assertThat(activeNodes).doesNotContain(3)
+ }
+ }
+
private fun waitForPrefetch(index: Int) {
rule.waitUntil {
activeNodes.contains(index) && activeMeasuredNodes.contains(index)
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridState.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridState.kt
index df4e4c2..42f4e83 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridState.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridState.kt
@@ -343,6 +343,25 @@
}
}
+ private fun cancelPrefetchIfVisibleItemsChanged(info: TvLazyGridLayoutInfo) {
+ if (lineToPrefetch != -1 && info.visibleItemsInfo.isNotEmpty()) {
+ val expectedLineToPrefetch = if (wasScrollingForward) {
+ info.visibleItemsInfo.last().let {
+ if (isVertical) it.row else it.column
+ } + 1
+ } else {
+ info.visibleItemsInfo.first().let {
+ if (isVertical) it.row else it.column
+ } - 1
+ }
+ if (lineToPrefetch != expectedLineToPrefetch) {
+ lineToPrefetch = -1
+ currentLinePrefetchHandles.forEach { it.cancel() }
+ currentLinePrefetchHandles.clear()
+ }
+ }
+ }
+
internal val prefetchState = LazyLayoutPrefetchState()
/**
@@ -374,6 +393,8 @@
result.firstVisibleLineScrollOffset != 0
numMeasurePasses++
+
+ cancelPrefetchIfVisibleItemsChanged(result)
}
/**
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListState.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListState.kt
index 3328e28..6330923 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListState.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListState.kt
@@ -365,6 +365,23 @@
result.firstVisibleItemScrollOffset != 0
numMeasurePasses++
+
+ cancelPrefetchIfVisibleItemsChanged(result)
+ }
+
+ private fun cancelPrefetchIfVisibleItemsChanged(info: TvLazyListLayoutInfo) {
+ if (indexToPrefetch != -1 && info.visibleItemsInfo.isNotEmpty()) {
+ val expectedPrefetchIndex = if (wasScrollingForward) {
+ info.visibleItemsInfo.last().index + 1
+ } else {
+ info.visibleItemsInfo.first().index - 1
+ }
+ if (indexToPrefetch != expectedPrefetchIndex) {
+ indexToPrefetch = -1
+ currentPrefetchHandle?.cancel()
+ currentPrefetchHandle = null
+ }
+ }
}
/**
diff --git a/vectordrawable/vectordrawable/lint-baseline.xml b/vectordrawable/vectordrawable/lint-baseline.xml
index a918dbd..f647f1f 100644
--- a/vectordrawable/vectordrawable/lint-baseline.xml
+++ b/vectordrawable/vectordrawable/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<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="UnknownNullness"
diff --git a/viewpager/viewpager/lint-baseline.xml b/viewpager/viewpager/lint-baseline.xml
index c9974a1..a252977 100644
--- a/viewpager/viewpager/lint-baseline.xml
+++ b/viewpager/viewpager/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<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="UnknownNullness"
diff --git a/wear/watchface/watchface-complications-data/lint-baseline.xml b/wear/watchface/watchface-complications-data/lint-baseline.xml
deleted file mode 100644
index af4f75c..0000000
--- a/wear/watchface/watchface-complications-data/lint-baseline.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?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="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="time_difference_short_days" formatted="false" msgid="3878057769320887026">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr-rCA/complication_strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="time_difference_short_days" formatted="false" msgid="3878057769320887026">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr/complication_strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="time_difference_short_hours" formatted="false" msgid="6016687406802669982">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr-rCA/complication_strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="time_difference_short_hours" formatted="false" msgid="6016687406802669982">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr/complication_strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="time_difference_short_minutes" formatted="false" msgid="6752732458902810711">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr-rCA/complication_strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="time_difference_short_minutes" formatted="false" msgid="6752732458902810711">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr/complication_strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="time_difference_words_days" formatted="false" msgid="5109682345086392533">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr-rCA/complication_strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="time_difference_words_days" formatted="false" msgid="5109682345086392533">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr/complication_strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="time_difference_words_hours" formatted="false" msgid="3172220157267000186">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr-rCA/complication_strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="time_difference_words_hours" formatted="false" msgid="3172220157267000186">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr/complication_strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="time_difference_words_minutes" formatted="false" msgid="529404827937478243">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr-rCA/complication_strings.xml"/>
- </issue>
-
- <issue
- id="MissingQuantity"
- message="For locale "fr" (French) the following quantity should also be defined: `many` (e.g. "1000000 de jours")"
- errorLine1=" <plurals name="time_difference_words_minutes" formatted="false" msgid="529404827937478243">"
- errorLine2=" ^">
- <location
- file="src/main/res/values-fr/complication_strings.xml"/>
- </issue>
-
-</issues>
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt
index 18896d4..18c41fe 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt
@@ -422,6 +422,8 @@
)
}
+ private var lastComplicationUpdate = Instant.EPOCH
+
private class ComplicationDataHistoryEntry(
val complicationData: ComplicationData,
val time: Instant
@@ -986,6 +988,7 @@
loadDrawablesAsynchronous: Boolean,
instant: Instant
) {
+ lastComplicationUpdate = instant
complicationHistory?.push(ComplicationDataHistoryEntry(complicationData, instant))
timelineComplicationData = complicationData
timelineEntries = complicationData.asWireComplicationData().timelineEntries?.map {
@@ -1210,6 +1213,7 @@
@OptIn(ComplicationExperimental::class)
writer.println("boundingArc=$boundingArc")
writer.println("complicationSlotBounds=$complicationSlotBounds")
+ writer.println("lastComplicationUpdate=$lastComplicationUpdate")
writer.println("data history")
complicationHistory?.let {
writer.increaseIndent()
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
index 51d8a7d..9fdf2f5 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
@@ -1926,7 +1926,6 @@
mutableWatchState.watchFaceInstanceId.value = sanitizeWatchFaceId(params.instanceId)
val watchState = mutableWatchState.asWatchState()
- interactiveInstanceId = mutableWatchState.watchFaceInstanceId.value
createWatchFaceInternal(
watchState,
fakeSurfaceHolder,
@@ -1968,7 +1967,6 @@
pendingInitialComplications = readComplicationDataCache(_context, params.instanceId)
}
- interactiveInstanceId = params.instanceId
createWatchFaceInternal(
watchState,
getWallpaperSurfaceHolderOverride(),
@@ -1977,6 +1975,7 @@
val instance = InteractiveWatchFaceImpl(this, params.instanceId)
InteractiveInstanceManager.addInstance(instance)
+ interactiveInstanceId = params.instanceId
return instance
}
@@ -2397,10 +2396,18 @@
override fun sendPreviewImageNeedsUpdateRequest() {
synchronized(lock) {
- lastPreviewImageNeedsUpdateRequest = interactiveInstanceId
+ if (this::interactiveInstanceId.isInitialized) {
+ lastPreviewImageNeedsUpdateRequest = interactiveInstanceId
- forEachListener("sendPreviewImageNeedsUpdateRequest") {
- it.onPreviewImageUpdateRequested(interactiveInstanceId)
+ forEachListener("sendPreviewImageNeedsUpdateRequest") {
+ it.onPreviewImageUpdateRequested(interactiveInstanceId)
+ }
+ } else {
+ Log.w(
+ TAG,
+ "Ignoring sendPreviewImageNeedsUpdateRequest because " +
+ "interactiveInstanceId not initialized"
+ )
}
}
}
diff --git a/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/MainActivity.java b/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/MainActivity.java
index d86f336..ddc135e 100644
--- a/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/MainActivity.java
+++ b/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/MainActivity.java
@@ -569,6 +569,17 @@
}
});
+ findViewById(R.id.enqueue_infinite_work_charging).setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ StressTest.queueLotsOfWorkers(
+ WorkManager.getInstance(MainActivity.this)
+ );
+ }
+ });
+
+
Button hundredJobExceptionButton = findViewById(R.id.create_hundred_job_exception);
// 100 Job limits are only enforced on API 24+.
if (Build.VERSION.SDK_INT >= 24) {
diff --git a/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/StressTest.kt b/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/StressTest.kt
new file mode 100644
index 0000000..48389e2
--- /dev/null
+++ b/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/StressTest.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+@file:JvmName("StressTest")
+package androidx.work.integration.testapp
+
+import android.util.Log
+import androidx.work.Constraints
+import androidx.work.ExistingWorkPolicy
+import androidx.work.NetworkType
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.WorkManager
+
+fun queueLotsOfWorkers(workManager: WorkManager) {
+ for (i in 1..1000) {
+ Log.i("TestWM", "Queueing $i worker")
+ val constraint = Constraints.Builder()
+ .setRequiredNetworkType(NetworkType.CONNECTED)
+ .build()
+ val uniqueName = "Worker-$i"
+
+ val worker = OneTimeWorkRequestBuilder<TestWorker>()
+ .setConstraints(constraint)
+ .build()
+
+ val worker2 = OneTimeWorkRequestBuilder<TestWorker>()
+ .setConstraints(constraint)
+ .build()
+
+ val worker3 = OneTimeWorkRequestBuilder<TestWorker>()
+ .setConstraints(constraint)
+ .build()
+
+ workManager.beginUniqueWork(uniqueName, ExistingWorkPolicy.KEEP, worker)
+ .then(worker2)
+ .then(worker3)
+ .enqueue()
+ }
+}
diff --git a/work/integration-tests/testapp/src/main/res/layout/activity_main.xml b/work/integration-tests/testapp/src/main/res/layout/activity_main.xml
index ced7f94..789d68f 100644
--- a/work/integration-tests/testapp/src/main/res/layout/activity_main.xml
+++ b/work/integration-tests/testapp/src/main/res/layout/activity_main.xml
@@ -343,5 +343,13 @@
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"/>
+ <Button android:text="@string/stress_test"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/stress_test"
+ android:layout_marginTop="12dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"/>
+
</LinearLayout>
</ScrollView>
diff --git a/work/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml b/work/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
index f56d600..91c735f 100644
--- a/work/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
+++ b/work/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
@@ -50,4 +50,5 @@
<integer name="notification_id">1</integer>
<string name="notification_title">Working</string>
<string name="cancel_constraint_tracking_worker">Cancel Constraint Tracking Worker</string>
+ <string name="stress_test">Stress Test</string>
</resources>
\ No newline at end of file
diff --git a/work/work-gcm/api/2.8.0-beta01.txt b/work/work-gcm/api/2.8.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/work/work-gcm/api/2.8.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/work/work-gcm/api/public_plus_experimental_2.8.0-beta01.txt b/work/work-gcm/api/public_plus_experimental_2.8.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/work/work-gcm/api/public_plus_experimental_2.8.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/work/work-gcm/api/res-2.8.0-beta01.txt b/work/work-gcm/api/res-2.8.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/work/work-gcm/api/res-2.8.0-beta01.txt
diff --git a/work/work-gcm/api/restricted_2.8.0-beta01.txt b/work/work-gcm/api/restricted_2.8.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/work/work-gcm/api/restricted_2.8.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/work/work-inspection/lint-baseline.xml b/work/work-inspection/lint-baseline.xml
index 677478e..2ddb484 100644
--- a/work/work-inspection/lint-baseline.xml
+++ b/work/work-inspection/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<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="RemoveWorkManagerInitializer"
diff --git a/work/work-multiprocess/api/2.8.0-beta01.txt b/work/work-multiprocess/api/2.8.0-beta01.txt
new file mode 100644
index 0000000..bd27cfb
--- /dev/null
+++ b/work/work-multiprocess/api/2.8.0-beta01.txt
@@ -0,0 +1,26 @@
+// Signature format: 4.0
+package androidx.work.multiprocess {
+
+ public abstract class RemoteCoroutineWorker extends androidx.work.multiprocess.RemoteListenableWorker {
+ ctor public RemoteCoroutineWorker(android.content.Context context, androidx.work.WorkerParameters parameters);
+ method public abstract suspend Object? doRemoteWork(kotlin.coroutines.Continuation<? super androidx.work.ListenableWorker.Result>);
+ method public final void onStopped();
+ method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result> startRemoteWork();
+ }
+
+ public abstract class RemoteListenableWorker extends androidx.work.ListenableWorker {
+ ctor public RemoteListenableWorker(android.content.Context, androidx.work.WorkerParameters);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startRemoteWork();
+ method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ field public static final String ARGUMENT_CLASS_NAME = "androidx.work.impl.workers.RemoteListenableWorker.ARGUMENT_CLASS_NAME";
+ field public static final String ARGUMENT_PACKAGE_NAME = "androidx.work.impl.workers.RemoteListenableWorker.ARGUMENT_PACKAGE_NAME";
+ }
+
+ public class RemoteWorkerService extends android.app.Service {
+ ctor public RemoteWorkerService();
+ method public android.os.IBinder? onBind(android.content.Intent);
+ }
+
+}
+
diff --git a/work/work-multiprocess/api/public_plus_experimental_2.8.0-beta01.txt b/work/work-multiprocess/api/public_plus_experimental_2.8.0-beta01.txt
new file mode 100644
index 0000000..bd27cfb
--- /dev/null
+++ b/work/work-multiprocess/api/public_plus_experimental_2.8.0-beta01.txt
@@ -0,0 +1,26 @@
+// Signature format: 4.0
+package androidx.work.multiprocess {
+
+ public abstract class RemoteCoroutineWorker extends androidx.work.multiprocess.RemoteListenableWorker {
+ ctor public RemoteCoroutineWorker(android.content.Context context, androidx.work.WorkerParameters parameters);
+ method public abstract suspend Object? doRemoteWork(kotlin.coroutines.Continuation<? super androidx.work.ListenableWorker.Result>);
+ method public final void onStopped();
+ method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result> startRemoteWork();
+ }
+
+ public abstract class RemoteListenableWorker extends androidx.work.ListenableWorker {
+ ctor public RemoteListenableWorker(android.content.Context, androidx.work.WorkerParameters);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startRemoteWork();
+ method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ field public static final String ARGUMENT_CLASS_NAME = "androidx.work.impl.workers.RemoteListenableWorker.ARGUMENT_CLASS_NAME";
+ field public static final String ARGUMENT_PACKAGE_NAME = "androidx.work.impl.workers.RemoteListenableWorker.ARGUMENT_PACKAGE_NAME";
+ }
+
+ public class RemoteWorkerService extends android.app.Service {
+ ctor public RemoteWorkerService();
+ method public android.os.IBinder? onBind(android.content.Intent);
+ }
+
+}
+
diff --git a/work/work-multiprocess/api/res-2.8.0-beta01.txt b/work/work-multiprocess/api/res-2.8.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/work/work-multiprocess/api/res-2.8.0-beta01.txt
diff --git a/work/work-multiprocess/api/restricted_2.8.0-beta01.txt b/work/work-multiprocess/api/restricted_2.8.0-beta01.txt
new file mode 100644
index 0000000..bd27cfb
--- /dev/null
+++ b/work/work-multiprocess/api/restricted_2.8.0-beta01.txt
@@ -0,0 +1,26 @@
+// Signature format: 4.0
+package androidx.work.multiprocess {
+
+ public abstract class RemoteCoroutineWorker extends androidx.work.multiprocess.RemoteListenableWorker {
+ ctor public RemoteCoroutineWorker(android.content.Context context, androidx.work.WorkerParameters parameters);
+ method public abstract suspend Object? doRemoteWork(kotlin.coroutines.Continuation<? super androidx.work.ListenableWorker.Result>);
+ method public final void onStopped();
+ method public final suspend Object? setProgress(androidx.work.Data data, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result> startRemoteWork();
+ }
+
+ public abstract class RemoteListenableWorker extends androidx.work.ListenableWorker {
+ ctor public RemoteListenableWorker(android.content.Context, androidx.work.WorkerParameters);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startRemoteWork();
+ method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ field public static final String ARGUMENT_CLASS_NAME = "androidx.work.impl.workers.RemoteListenableWorker.ARGUMENT_CLASS_NAME";
+ field public static final String ARGUMENT_PACKAGE_NAME = "androidx.work.impl.workers.RemoteListenableWorker.ARGUMENT_PACKAGE_NAME";
+ }
+
+ public class RemoteWorkerService extends android.app.Service {
+ ctor public RemoteWorkerService();
+ method public android.os.IBinder? onBind(android.content.Intent);
+ }
+
+}
+
diff --git a/work/work-runtime-ktx/api/2.8.0-beta01.txt b/work/work-runtime-ktx/api/2.8.0-beta01.txt
new file mode 100644
index 0000000..efdea4c
--- /dev/null
+++ b/work/work-runtime-ktx/api/2.8.0-beta01.txt
@@ -0,0 +1,30 @@
+// 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 ListenableFutureKt {
+ }
+
+ 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/public_plus_experimental_2.8.0-beta01.txt b/work/work-runtime-ktx/api/public_plus_experimental_2.8.0-beta01.txt
new file mode 100644
index 0000000..efdea4c
--- /dev/null
+++ b/work/work-runtime-ktx/api/public_plus_experimental_2.8.0-beta01.txt
@@ -0,0 +1,30 @@
+// 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 ListenableFutureKt {
+ }
+
+ 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/res-2.8.0-beta01.txt b/work/work-runtime-ktx/api/res-2.8.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/work/work-runtime-ktx/api/res-2.8.0-beta01.txt
diff --git a/work/work-runtime-ktx/api/restricted_2.8.0-beta01.txt b/work/work-runtime-ktx/api/restricted_2.8.0-beta01.txt
new file mode 100644
index 0000000..efdea4c
--- /dev/null
+++ b/work/work-runtime-ktx/api/restricted_2.8.0-beta01.txt
@@ -0,0 +1,30 @@
+// 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 ListenableFutureKt {
+ }
+
+ 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/api/2.8.0-beta01.txt b/work/work-runtime/api/2.8.0-beta01.txt
new file mode 100644
index 0000000..4519d02
--- /dev/null
+++ b/work/work-runtime/api/2.8.0-beta01.txt
@@ -0,0 +1,499 @@
+// Signature format: 4.0
+package androidx.work {
+
+ public final class ArrayCreatingInputMerger extends androidx.work.InputMerger {
+ ctor public ArrayCreatingInputMerger();
+ method public androidx.work.Data merge(java.util.List<androidx.work.Data> inputs);
+ }
+
+ public enum BackoffPolicy {
+ method public static androidx.work.BackoffPolicy valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.BackoffPolicy[] values();
+ enum_constant public static final androidx.work.BackoffPolicy EXPONENTIAL;
+ enum_constant public static final androidx.work.BackoffPolicy LINEAR;
+ }
+
+ public final class Configuration {
+ method public String? getDefaultProcessName();
+ method public java.util.concurrent.Executor getExecutor();
+ method public androidx.work.InitializationExceptionHandler? getInitializationExceptionHandler();
+ method public androidx.work.InputMergerFactory getInputMergerFactory();
+ method public int getMaxJobSchedulerId();
+ method public int getMinJobSchedulerId();
+ method public androidx.work.RunnableScheduler getRunnableScheduler();
+ method public androidx.work.SchedulingExceptionHandler? getSchedulingExceptionHandler();
+ method public java.util.concurrent.Executor getTaskExecutor();
+ method public androidx.work.WorkerFactory getWorkerFactory();
+ field public static final int MIN_SCHEDULER_LIMIT = 20; // 0x14
+ }
+
+ public static final class Configuration.Builder {
+ ctor public Configuration.Builder();
+ method public androidx.work.Configuration build();
+ method public androidx.work.Configuration.Builder setDefaultProcessName(String);
+ method public androidx.work.Configuration.Builder setExecutor(java.util.concurrent.Executor);
+ method public androidx.work.Configuration.Builder setInitializationExceptionHandler(androidx.work.InitializationExceptionHandler);
+ method public androidx.work.Configuration.Builder setInputMergerFactory(androidx.work.InputMergerFactory);
+ method public androidx.work.Configuration.Builder setJobSchedulerJobIdRange(int, int);
+ method public androidx.work.Configuration.Builder setMaxSchedulerLimit(int);
+ method public androidx.work.Configuration.Builder setMinimumLoggingLevel(int);
+ method public androidx.work.Configuration.Builder setRunnableScheduler(androidx.work.RunnableScheduler);
+ method public androidx.work.Configuration.Builder setSchedulingExceptionHandler(androidx.work.SchedulingExceptionHandler);
+ method public androidx.work.Configuration.Builder setTaskExecutor(java.util.concurrent.Executor);
+ method public androidx.work.Configuration.Builder setWorkerFactory(androidx.work.WorkerFactory);
+ }
+
+ public static interface Configuration.Provider {
+ method public androidx.work.Configuration getWorkManagerConfiguration();
+ }
+
+ public final class Constraints {
+ ctor public Constraints(optional @androidx.room.ColumnInfo(name="required_network_type") androidx.work.NetworkType requiredNetworkType, optional @androidx.room.ColumnInfo(name="requires_charging") boolean requiresCharging, optional @androidx.room.ColumnInfo(name="requires_device_idle") boolean requiresDeviceIdle, optional @androidx.room.ColumnInfo(name="requires_battery_not_low") boolean requiresBatteryNotLow, optional @androidx.room.ColumnInfo(name="requires_storage_not_low") boolean requiresStorageNotLow, optional @androidx.room.ColumnInfo(name="trigger_content_update_delay") long contentTriggerUpdateDelayMillis, optional @androidx.room.ColumnInfo(name="trigger_max_content_delay") long contentTriggerMaxDelayMillis, optional @androidx.room.ColumnInfo(name="content_uri_triggers") java.util.Set<androidx.work.Constraints.ContentUriTrigger> contentUriTriggers);
+ ctor public Constraints(androidx.work.Constraints other);
+ method public long getContentTriggerMaxDelayMillis();
+ method public long getContentTriggerUpdateDelayMillis();
+ method public java.util.Set<androidx.work.Constraints.ContentUriTrigger> getContentUriTriggers();
+ method public androidx.work.NetworkType getRequiredNetworkType();
+ method public boolean requiresBatteryNotLow();
+ method public boolean requiresCharging();
+ method @RequiresApi(23) public boolean requiresDeviceIdle();
+ method public boolean requiresStorageNotLow();
+ property public final long contentTriggerMaxDelayMillis;
+ property public final long contentTriggerUpdateDelayMillis;
+ property public final java.util.Set<androidx.work.Constraints.ContentUriTrigger> contentUriTriggers;
+ property public final androidx.work.NetworkType requiredNetworkType;
+ field public static final androidx.work.Constraints.Companion Companion;
+ field public static final androidx.work.Constraints NONE;
+ }
+
+ public static final class Constraints.Builder {
+ ctor public Constraints.Builder();
+ method @RequiresApi(24) public androidx.work.Constraints.Builder addContentUriTrigger(android.net.Uri uri, boolean triggerForDescendants);
+ method public androidx.work.Constraints build();
+ method public androidx.work.Constraints.Builder setRequiredNetworkType(androidx.work.NetworkType networkType);
+ method public androidx.work.Constraints.Builder setRequiresBatteryNotLow(boolean requiresBatteryNotLow);
+ method public androidx.work.Constraints.Builder setRequiresCharging(boolean requiresCharging);
+ method @RequiresApi(23) public androidx.work.Constraints.Builder setRequiresDeviceIdle(boolean requiresDeviceIdle);
+ method public androidx.work.Constraints.Builder setRequiresStorageNotLow(boolean requiresStorageNotLow);
+ method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(long duration, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(java.time.Duration duration);
+ method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(long duration, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(java.time.Duration duration);
+ }
+
+ public static final class Constraints.Companion {
+ }
+
+ public static final class Constraints.ContentUriTrigger {
+ ctor public Constraints.ContentUriTrigger(android.net.Uri uri, boolean isTriggeredForDescendants);
+ method public android.net.Uri getUri();
+ method public boolean isTriggeredForDescendants();
+ property public final boolean isTriggeredForDescendants;
+ property public final android.net.Uri uri;
+ }
+
+ public final class Data {
+ ctor public Data(androidx.work.Data);
+ method @androidx.room.TypeConverter public static androidx.work.Data fromByteArray(byte[]);
+ method public boolean getBoolean(String, boolean);
+ method public boolean[]? getBooleanArray(String);
+ method public byte getByte(String, byte);
+ method public byte[]? getByteArray(String);
+ method public double getDouble(String, double);
+ method public double[]? getDoubleArray(String);
+ method public float getFloat(String, float);
+ method public float[]? getFloatArray(String);
+ method public int getInt(String, int);
+ method public int[]? getIntArray(String);
+ method public java.util.Map<java.lang.String!,java.lang.Object!> getKeyValueMap();
+ method public long getLong(String, long);
+ method public long[]? getLongArray(String);
+ method public String? getString(String);
+ method public String![]? getStringArray(String);
+ method public <T> boolean hasKeyWithValueOfType(String, Class<T!>);
+ method public byte[] toByteArray();
+ field public static final androidx.work.Data EMPTY;
+ field public static final int MAX_DATA_BYTES = 10240; // 0x2800
+ }
+
+ public static final class Data.Builder {
+ ctor public Data.Builder();
+ method public androidx.work.Data build();
+ method public androidx.work.Data.Builder putAll(androidx.work.Data);
+ method public androidx.work.Data.Builder putAll(java.util.Map<java.lang.String!,java.lang.Object!>);
+ method public androidx.work.Data.Builder putBoolean(String, boolean);
+ method public androidx.work.Data.Builder putBooleanArray(String, boolean[]);
+ method public androidx.work.Data.Builder putByte(String, byte);
+ method public androidx.work.Data.Builder putByteArray(String, byte[]);
+ method public androidx.work.Data.Builder putDouble(String, double);
+ method public androidx.work.Data.Builder putDoubleArray(String, double[]);
+ method public androidx.work.Data.Builder putFloat(String, float);
+ method public androidx.work.Data.Builder putFloatArray(String, float[]);
+ method public androidx.work.Data.Builder putInt(String, int);
+ method public androidx.work.Data.Builder putIntArray(String, int[]);
+ method public androidx.work.Data.Builder putLong(String, long);
+ method public androidx.work.Data.Builder putLongArray(String, long[]);
+ method public androidx.work.Data.Builder putString(String, String?);
+ method public androidx.work.Data.Builder putStringArray(String, String![]);
+ }
+
+ public class DelegatingWorkerFactory extends androidx.work.WorkerFactory {
+ ctor public DelegatingWorkerFactory();
+ method public final void addFactory(androidx.work.WorkerFactory);
+ method public final androidx.work.ListenableWorker? createWorker(android.content.Context, String, androidx.work.WorkerParameters);
+ }
+
+ public enum ExistingPeriodicWorkPolicy {
+ method public static androidx.work.ExistingPeriodicWorkPolicy valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.ExistingPeriodicWorkPolicy[] values();
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy CANCEL_AND_REENQUEUE;
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy KEEP;
+ enum_constant @Deprecated public static final androidx.work.ExistingPeriodicWorkPolicy REPLACE;
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy UPDATE;
+ }
+
+ public enum ExistingWorkPolicy {
+ method public static androidx.work.ExistingWorkPolicy valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.ExistingWorkPolicy[] values();
+ enum_constant public static final androidx.work.ExistingWorkPolicy APPEND;
+ enum_constant public static final androidx.work.ExistingWorkPolicy APPEND_OR_REPLACE;
+ enum_constant public static final androidx.work.ExistingWorkPolicy KEEP;
+ enum_constant public static final androidx.work.ExistingWorkPolicy REPLACE;
+ }
+
+ public final class ForegroundInfo {
+ ctor public ForegroundInfo(int, android.app.Notification);
+ ctor public ForegroundInfo(int, android.app.Notification, int);
+ method public int getForegroundServiceType();
+ method public android.app.Notification getNotification();
+ method public int getNotificationId();
+ }
+
+ public interface ForegroundUpdater {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setForegroundAsync(android.content.Context, java.util.UUID, androidx.work.ForegroundInfo);
+ }
+
+ public interface InitializationExceptionHandler {
+ method public void handleException(Throwable);
+ }
+
+ public abstract class InputMerger {
+ ctor public InputMerger();
+ method public abstract androidx.work.Data merge(java.util.List<androidx.work.Data!>);
+ }
+
+ public abstract class InputMergerFactory {
+ ctor public InputMergerFactory();
+ method public abstract androidx.work.InputMerger? createInputMerger(String);
+ }
+
+ public abstract class ListenableWorker {
+ ctor public ListenableWorker(android.content.Context, androidx.work.WorkerParameters);
+ method public final android.content.Context getApplicationContext();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.work.ForegroundInfo!> getForegroundInfoAsync();
+ method public final java.util.UUID getId();
+ method public final androidx.work.Data getInputData();
+ method @RequiresApi(28) public final android.net.Network? getNetwork();
+ method @IntRange(from=0) public final int getRunAttemptCount();
+ method public final java.util.Set<java.lang.String!> getTags();
+ method @RequiresApi(24) public final java.util.List<java.lang.String!> getTriggeredContentAuthorities();
+ method @RequiresApi(24) public final java.util.List<android.net.Uri!> getTriggeredContentUris();
+ method public final boolean isStopped();
+ method public void onStopped();
+ method public final com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setForegroundAsync(androidx.work.ForegroundInfo);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setProgressAsync(androidx.work.Data);
+ method @MainThread public abstract com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ }
+
+ public abstract static class ListenableWorker.Result {
+ method public static androidx.work.ListenableWorker.Result failure();
+ method public static androidx.work.ListenableWorker.Result failure(androidx.work.Data);
+ method public abstract androidx.work.Data getOutputData();
+ method public static androidx.work.ListenableWorker.Result retry();
+ method public static androidx.work.ListenableWorker.Result success();
+ method public static androidx.work.ListenableWorker.Result success(androidx.work.Data);
+ }
+
+ public enum NetworkType {
+ method public static androidx.work.NetworkType valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.NetworkType[] values();
+ enum_constant public static final androidx.work.NetworkType CONNECTED;
+ enum_constant public static final androidx.work.NetworkType METERED;
+ enum_constant public static final androidx.work.NetworkType NOT_REQUIRED;
+ enum_constant public static final androidx.work.NetworkType NOT_ROAMING;
+ enum_constant @RequiresApi(30) public static final androidx.work.NetworkType TEMPORARILY_UNMETERED;
+ enum_constant public static final androidx.work.NetworkType UNMETERED;
+ }
+
+ public final class OneTimeWorkRequest extends androidx.work.WorkRequest {
+ method public static androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker> workerClass);
+ method public static java.util.List<androidx.work.OneTimeWorkRequest> from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>> workerClasses);
+ field public static final androidx.work.OneTimeWorkRequest.Companion Companion;
+ }
+
+ public static final class OneTimeWorkRequest.Builder extends androidx.work.WorkRequest.Builder<androidx.work.OneTimeWorkRequest.Builder,androidx.work.OneTimeWorkRequest> {
+ ctor public OneTimeWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass);
+ method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.InputMerger> inputMerger);
+ }
+
+ public static final class OneTimeWorkRequest.Companion {
+ method public androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker> workerClass);
+ method public java.util.List<androidx.work.OneTimeWorkRequest> from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>> workerClasses);
+ }
+
+ public final class OneTimeWorkRequestKt {
+ method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.OneTimeWorkRequest.Builder! OneTimeWorkRequestBuilder();
+ method public static inline androidx.work.OneTimeWorkRequest.Builder setInputMerger(androidx.work.OneTimeWorkRequest.Builder, kotlin.reflect.KClass<? extends androidx.work.InputMerger> inputMerger);
+ }
+
+ public interface Operation {
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.work.Operation.State.SUCCESS!> getResult();
+ method public androidx.lifecycle.LiveData<androidx.work.Operation.State!> getState();
+ }
+
+ public abstract static class Operation.State {
+ }
+
+ public static final class Operation.State.FAILURE extends androidx.work.Operation.State {
+ ctor public Operation.State.FAILURE(Throwable);
+ method public Throwable getThrowable();
+ }
+
+ public static final class Operation.State.IN_PROGRESS extends androidx.work.Operation.State {
+ }
+
+ public static final class Operation.State.SUCCESS extends androidx.work.Operation.State {
+ }
+
+ public enum OutOfQuotaPolicy {
+ method public static androidx.work.OutOfQuotaPolicy valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.OutOfQuotaPolicy[] values();
+ enum_constant public static final androidx.work.OutOfQuotaPolicy DROP_WORK_REQUEST;
+ enum_constant public static final androidx.work.OutOfQuotaPolicy RUN_AS_NON_EXPEDITED_WORK_REQUEST;
+ }
+
+ public final class OverwritingInputMerger extends androidx.work.InputMerger {
+ ctor public OverwritingInputMerger();
+ method public androidx.work.Data merge(java.util.List<androidx.work.Data!>);
+ }
+
+ public final class PeriodicWorkRequest extends androidx.work.WorkRequest {
+ field public static final androidx.work.PeriodicWorkRequest.Companion Companion;
+ field public static final long MIN_PERIODIC_FLEX_MILLIS = 300000L; // 0x493e0L
+ field public static final long MIN_PERIODIC_INTERVAL_MILLIS = 900000L; // 0xdbba0L
+ }
+
+ public static final class PeriodicWorkRequest.Builder extends androidx.work.WorkRequest.Builder<androidx.work.PeriodicWorkRequest.Builder,androidx.work.PeriodicWorkRequest> {
+ ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
+ ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, java.time.Duration repeatInterval);
+ ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexInterval, java.util.concurrent.TimeUnit flexIntervalTimeUnit);
+ ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, java.time.Duration repeatInterval, java.time.Duration flexInterval);
+ }
+
+ public static final class PeriodicWorkRequest.Companion {
+ }
+
+ public final class PeriodicWorkRequestKt {
+ method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
+ method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval);
+ method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexTimeInterval, java.util.concurrent.TimeUnit flexTimeIntervalUnit);
+ method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval, java.time.Duration flexTimeInterval);
+ }
+
+ public interface ProgressUpdater {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> updateProgress(android.content.Context, java.util.UUID, androidx.work.Data);
+ }
+
+ public interface RunnableScheduler {
+ method public void cancel(Runnable);
+ method public void scheduleWithDelay(@IntRange(from=0) long, Runnable);
+ }
+
+ public interface SchedulingExceptionHandler {
+ method public void handleException(Throwable);
+ }
+
+ public abstract class WorkContinuation {
+ ctor public WorkContinuation();
+ method public static androidx.work.WorkContinuation combine(java.util.List<androidx.work.WorkContinuation!>);
+ method public abstract androidx.work.Operation enqueue();
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfos();
+ method public abstract androidx.lifecycle.LiveData<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosLiveData();
+ method public final androidx.work.WorkContinuation then(androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.WorkContinuation then(java.util.List<androidx.work.OneTimeWorkRequest!>);
+ }
+
+ public final class WorkInfo {
+ method public int getGeneration();
+ method public java.util.UUID getId();
+ method public androidx.work.Data getOutputData();
+ method public androidx.work.Data getProgress();
+ method @IntRange(from=0) public int getRunAttemptCount();
+ method public androidx.work.WorkInfo.State getState();
+ method public java.util.Set<java.lang.String!> getTags();
+ }
+
+ public enum WorkInfo.State {
+ method public boolean isFinished();
+ enum_constant public static final androidx.work.WorkInfo.State BLOCKED;
+ enum_constant public static final androidx.work.WorkInfo.State CANCELLED;
+ enum_constant public static final androidx.work.WorkInfo.State ENQUEUED;
+ enum_constant public static final androidx.work.WorkInfo.State FAILED;
+ enum_constant public static final androidx.work.WorkInfo.State RUNNING;
+ enum_constant public static final androidx.work.WorkInfo.State SUCCEEDED;
+ }
+
+ public abstract class WorkManager {
+ method public final androidx.work.WorkContinuation beginUniqueWork(String, androidx.work.ExistingWorkPolicy, androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.WorkContinuation beginUniqueWork(String, androidx.work.ExistingWorkPolicy, java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public final androidx.work.WorkContinuation beginWith(androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.WorkContinuation beginWith(java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public abstract androidx.work.Operation cancelAllWork();
+ method public abstract androidx.work.Operation cancelAllWorkByTag(String);
+ method public abstract androidx.work.Operation cancelUniqueWork(String);
+ method public abstract androidx.work.Operation cancelWorkById(java.util.UUID);
+ method public abstract android.app.PendingIntent createCancelPendingIntent(java.util.UUID);
+ method public final androidx.work.Operation enqueue(androidx.work.WorkRequest);
+ method public abstract androidx.work.Operation enqueue(java.util.List<? extends androidx.work.WorkRequest>);
+ method public abstract androidx.work.Operation enqueueUniquePeriodicWork(String, androidx.work.ExistingPeriodicWorkPolicy, androidx.work.PeriodicWorkRequest);
+ method public androidx.work.Operation enqueueUniqueWork(String, androidx.work.ExistingWorkPolicy, androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.Operation enqueueUniqueWork(String, androidx.work.ExistingWorkPolicy, java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public abstract androidx.work.Configuration getConfiguration();
+ method @Deprecated public static androidx.work.WorkManager getInstance();
+ method public static androidx.work.WorkManager getInstance(android.content.Context);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Long!> getLastCancelAllTimeMillis();
+ method public abstract androidx.lifecycle.LiveData<java.lang.Long!> getLastCancelAllTimeMillisLiveData();
+ method public abstract com.google.common.util.concurrent.ListenableFuture<androidx.work.WorkInfo!> getWorkInfoById(java.util.UUID);
+ method public abstract androidx.lifecycle.LiveData<androidx.work.WorkInfo!> getWorkInfoByIdLiveData(java.util.UUID);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfos(androidx.work.WorkQuery);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosByTag(String);
+ method public abstract androidx.lifecycle.LiveData<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosByTagLiveData(String);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosForUniqueWork(String);
+ method public abstract androidx.lifecycle.LiveData<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosForUniqueWorkLiveData(String);
+ method public abstract androidx.lifecycle.LiveData<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosLiveData(androidx.work.WorkQuery);
+ method public static void initialize(android.content.Context, androidx.work.Configuration);
+ method public static boolean isInitialized();
+ method public abstract androidx.work.Operation pruneWork();
+ method public abstract com.google.common.util.concurrent.ListenableFuture<androidx.work.WorkManager.UpdateResult!> updateWork(androidx.work.WorkRequest);
+ }
+
+ public enum WorkManager.UpdateResult {
+ enum_constant public static final androidx.work.WorkManager.UpdateResult APPLIED_FOR_NEXT_RUN;
+ enum_constant public static final androidx.work.WorkManager.UpdateResult APPLIED_IMMEDIATELY;
+ enum_constant public static final androidx.work.WorkManager.UpdateResult NOT_APPLIED;
+ }
+
+ public final class WorkManagerInitializer implements androidx.startup.Initializer<androidx.work.WorkManager> {
+ ctor public WorkManagerInitializer();
+ method public androidx.work.WorkManager create(android.content.Context);
+ method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>!> dependencies();
+ }
+
+ public final class WorkQuery {
+ method public static androidx.work.WorkQuery fromIds(java.util.List<java.util.UUID!>);
+ method public static androidx.work.WorkQuery fromIds(java.util.UUID!...);
+ method public static androidx.work.WorkQuery fromStates(java.util.List<androidx.work.WorkInfo.State!>);
+ method public static androidx.work.WorkQuery fromStates(androidx.work.WorkInfo.State!...);
+ method public static androidx.work.WorkQuery fromTags(java.util.List<java.lang.String!>);
+ method public static androidx.work.WorkQuery fromTags(java.lang.String!...);
+ method public static androidx.work.WorkQuery fromUniqueWorkNames(java.lang.String!...);
+ method public static androidx.work.WorkQuery fromUniqueWorkNames(java.util.List<java.lang.String!>);
+ method public java.util.List<java.util.UUID!> getIds();
+ method public java.util.List<androidx.work.WorkInfo.State!> getStates();
+ method public java.util.List<java.lang.String!> getTags();
+ method public java.util.List<java.lang.String!> getUniqueWorkNames();
+ }
+
+ public static final class WorkQuery.Builder {
+ method public androidx.work.WorkQuery.Builder addIds(java.util.List<java.util.UUID!>);
+ method public androidx.work.WorkQuery.Builder addStates(java.util.List<androidx.work.WorkInfo.State!>);
+ method public androidx.work.WorkQuery.Builder addTags(java.util.List<java.lang.String!>);
+ method public androidx.work.WorkQuery.Builder addUniqueWorkNames(java.util.List<java.lang.String!>);
+ method public androidx.work.WorkQuery build();
+ method public static androidx.work.WorkQuery.Builder fromIds(java.util.List<java.util.UUID!>);
+ method public static androidx.work.WorkQuery.Builder fromStates(java.util.List<androidx.work.WorkInfo.State!>);
+ method public static androidx.work.WorkQuery.Builder fromTags(java.util.List<java.lang.String!>);
+ method public static androidx.work.WorkQuery.Builder fromUniqueWorkNames(java.util.List<java.lang.String!>);
+ }
+
+ public abstract class WorkRequest {
+ method public java.util.UUID getId();
+ property public java.util.UUID id;
+ field public static final androidx.work.WorkRequest.Companion Companion;
+ field public static final long DEFAULT_BACKOFF_DELAY_MILLIS = 30000L; // 0x7530L
+ field public static final long MAX_BACKOFF_MILLIS = 18000000L; // 0x112a880L
+ field public static final long MIN_BACKOFF_MILLIS = 10000L; // 0x2710L
+ }
+
+ public abstract static class WorkRequest.Builder<B extends androidx.work.WorkRequest.Builder<B, ?>, W extends androidx.work.WorkRequest> {
+ method public final B addTag(String tag);
+ method public final W build();
+ method public final B keepResultsForAtLeast(long duration, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration duration);
+ method public final B setBackoffCriteria(androidx.work.BackoffPolicy backoffPolicy, long backoffDelay, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy backoffPolicy, java.time.Duration duration);
+ method public final B setConstraints(androidx.work.Constraints constraints);
+ method public B setExpedited(androidx.work.OutOfQuotaPolicy policy);
+ method public final B setId(java.util.UUID id);
+ method public B setInitialDelay(long duration, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public B setInitialDelay(java.time.Duration duration);
+ method public final B setInputData(androidx.work.Data inputData);
+ }
+
+ public static final class WorkRequest.Companion {
+ }
+
+ public abstract class Worker extends androidx.work.ListenableWorker {
+ ctor public Worker(android.content.Context, androidx.work.WorkerParameters);
+ method @WorkerThread public abstract androidx.work.ListenableWorker.Result doWork();
+ method @WorkerThread public androidx.work.ForegroundInfo getForegroundInfo();
+ method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ }
+
+ public abstract class WorkerFactory {
+ ctor public WorkerFactory();
+ method public abstract androidx.work.ListenableWorker? createWorker(android.content.Context, String, androidx.work.WorkerParameters);
+ }
+
+ public final class WorkerParameters {
+ method @IntRange(from=0) public int getGeneration();
+ method public java.util.UUID getId();
+ method public androidx.work.Data getInputData();
+ method @RequiresApi(28) public android.net.Network? getNetwork();
+ method @IntRange(from=0) public int getRunAttemptCount();
+ method public java.util.Set<java.lang.String!> getTags();
+ method @RequiresApi(24) public java.util.List<java.lang.String!> getTriggeredContentAuthorities();
+ method @RequiresApi(24) public java.util.List<android.net.Uri!> getTriggeredContentUris();
+ }
+
+}
+
+package androidx.work.multiprocess {
+
+ public abstract class RemoteWorkContinuation {
+ method public static androidx.work.multiprocess.RemoteWorkContinuation combine(java.util.List<androidx.work.multiprocess.RemoteWorkContinuation!>);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueue();
+ method public final androidx.work.multiprocess.RemoteWorkContinuation then(androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.multiprocess.RemoteWorkContinuation then(java.util.List<androidx.work.OneTimeWorkRequest!>);
+ }
+
+ public abstract class RemoteWorkManager {
+ method public final androidx.work.multiprocess.RemoteWorkContinuation beginUniqueWork(String, androidx.work.ExistingWorkPolicy, androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.multiprocess.RemoteWorkContinuation beginUniqueWork(String, androidx.work.ExistingWorkPolicy, java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public final androidx.work.multiprocess.RemoteWorkContinuation beginWith(androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.multiprocess.RemoteWorkContinuation beginWith(java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelAllWork();
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelAllWorkByTag(String);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelUniqueWork(String);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelWorkById(java.util.UUID);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueue(androidx.work.WorkRequest);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueue(java.util.List<androidx.work.WorkRequest!>);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueueUniquePeriodicWork(String, androidx.work.ExistingPeriodicWorkPolicy, androidx.work.PeriodicWorkRequest);
+ method public final com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueueUniqueWork(String, androidx.work.ExistingWorkPolicy, androidx.work.OneTimeWorkRequest);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueueUniqueWork(String, androidx.work.ExistingWorkPolicy, java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public static androidx.work.multiprocess.RemoteWorkManager getInstance(android.content.Context);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfos(androidx.work.WorkQuery);
+ }
+
+}
+
diff --git a/work/work-runtime/api/public_plus_experimental_2.8.0-beta01.txt b/work/work-runtime/api/public_plus_experimental_2.8.0-beta01.txt
new file mode 100644
index 0000000..4519d02
--- /dev/null
+++ b/work/work-runtime/api/public_plus_experimental_2.8.0-beta01.txt
@@ -0,0 +1,499 @@
+// Signature format: 4.0
+package androidx.work {
+
+ public final class ArrayCreatingInputMerger extends androidx.work.InputMerger {
+ ctor public ArrayCreatingInputMerger();
+ method public androidx.work.Data merge(java.util.List<androidx.work.Data> inputs);
+ }
+
+ public enum BackoffPolicy {
+ method public static androidx.work.BackoffPolicy valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.BackoffPolicy[] values();
+ enum_constant public static final androidx.work.BackoffPolicy EXPONENTIAL;
+ enum_constant public static final androidx.work.BackoffPolicy LINEAR;
+ }
+
+ public final class Configuration {
+ method public String? getDefaultProcessName();
+ method public java.util.concurrent.Executor getExecutor();
+ method public androidx.work.InitializationExceptionHandler? getInitializationExceptionHandler();
+ method public androidx.work.InputMergerFactory getInputMergerFactory();
+ method public int getMaxJobSchedulerId();
+ method public int getMinJobSchedulerId();
+ method public androidx.work.RunnableScheduler getRunnableScheduler();
+ method public androidx.work.SchedulingExceptionHandler? getSchedulingExceptionHandler();
+ method public java.util.concurrent.Executor getTaskExecutor();
+ method public androidx.work.WorkerFactory getWorkerFactory();
+ field public static final int MIN_SCHEDULER_LIMIT = 20; // 0x14
+ }
+
+ public static final class Configuration.Builder {
+ ctor public Configuration.Builder();
+ method public androidx.work.Configuration build();
+ method public androidx.work.Configuration.Builder setDefaultProcessName(String);
+ method public androidx.work.Configuration.Builder setExecutor(java.util.concurrent.Executor);
+ method public androidx.work.Configuration.Builder setInitializationExceptionHandler(androidx.work.InitializationExceptionHandler);
+ method public androidx.work.Configuration.Builder setInputMergerFactory(androidx.work.InputMergerFactory);
+ method public androidx.work.Configuration.Builder setJobSchedulerJobIdRange(int, int);
+ method public androidx.work.Configuration.Builder setMaxSchedulerLimit(int);
+ method public androidx.work.Configuration.Builder setMinimumLoggingLevel(int);
+ method public androidx.work.Configuration.Builder setRunnableScheduler(androidx.work.RunnableScheduler);
+ method public androidx.work.Configuration.Builder setSchedulingExceptionHandler(androidx.work.SchedulingExceptionHandler);
+ method public androidx.work.Configuration.Builder setTaskExecutor(java.util.concurrent.Executor);
+ method public androidx.work.Configuration.Builder setWorkerFactory(androidx.work.WorkerFactory);
+ }
+
+ public static interface Configuration.Provider {
+ method public androidx.work.Configuration getWorkManagerConfiguration();
+ }
+
+ public final class Constraints {
+ ctor public Constraints(optional @androidx.room.ColumnInfo(name="required_network_type") androidx.work.NetworkType requiredNetworkType, optional @androidx.room.ColumnInfo(name="requires_charging") boolean requiresCharging, optional @androidx.room.ColumnInfo(name="requires_device_idle") boolean requiresDeviceIdle, optional @androidx.room.ColumnInfo(name="requires_battery_not_low") boolean requiresBatteryNotLow, optional @androidx.room.ColumnInfo(name="requires_storage_not_low") boolean requiresStorageNotLow, optional @androidx.room.ColumnInfo(name="trigger_content_update_delay") long contentTriggerUpdateDelayMillis, optional @androidx.room.ColumnInfo(name="trigger_max_content_delay") long contentTriggerMaxDelayMillis, optional @androidx.room.ColumnInfo(name="content_uri_triggers") java.util.Set<androidx.work.Constraints.ContentUriTrigger> contentUriTriggers);
+ ctor public Constraints(androidx.work.Constraints other);
+ method public long getContentTriggerMaxDelayMillis();
+ method public long getContentTriggerUpdateDelayMillis();
+ method public java.util.Set<androidx.work.Constraints.ContentUriTrigger> getContentUriTriggers();
+ method public androidx.work.NetworkType getRequiredNetworkType();
+ method public boolean requiresBatteryNotLow();
+ method public boolean requiresCharging();
+ method @RequiresApi(23) public boolean requiresDeviceIdle();
+ method public boolean requiresStorageNotLow();
+ property public final long contentTriggerMaxDelayMillis;
+ property public final long contentTriggerUpdateDelayMillis;
+ property public final java.util.Set<androidx.work.Constraints.ContentUriTrigger> contentUriTriggers;
+ property public final androidx.work.NetworkType requiredNetworkType;
+ field public static final androidx.work.Constraints.Companion Companion;
+ field public static final androidx.work.Constraints NONE;
+ }
+
+ public static final class Constraints.Builder {
+ ctor public Constraints.Builder();
+ method @RequiresApi(24) public androidx.work.Constraints.Builder addContentUriTrigger(android.net.Uri uri, boolean triggerForDescendants);
+ method public androidx.work.Constraints build();
+ method public androidx.work.Constraints.Builder setRequiredNetworkType(androidx.work.NetworkType networkType);
+ method public androidx.work.Constraints.Builder setRequiresBatteryNotLow(boolean requiresBatteryNotLow);
+ method public androidx.work.Constraints.Builder setRequiresCharging(boolean requiresCharging);
+ method @RequiresApi(23) public androidx.work.Constraints.Builder setRequiresDeviceIdle(boolean requiresDeviceIdle);
+ method public androidx.work.Constraints.Builder setRequiresStorageNotLow(boolean requiresStorageNotLow);
+ method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(long duration, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(java.time.Duration duration);
+ method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(long duration, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(java.time.Duration duration);
+ }
+
+ public static final class Constraints.Companion {
+ }
+
+ public static final class Constraints.ContentUriTrigger {
+ ctor public Constraints.ContentUriTrigger(android.net.Uri uri, boolean isTriggeredForDescendants);
+ method public android.net.Uri getUri();
+ method public boolean isTriggeredForDescendants();
+ property public final boolean isTriggeredForDescendants;
+ property public final android.net.Uri uri;
+ }
+
+ public final class Data {
+ ctor public Data(androidx.work.Data);
+ method @androidx.room.TypeConverter public static androidx.work.Data fromByteArray(byte[]);
+ method public boolean getBoolean(String, boolean);
+ method public boolean[]? getBooleanArray(String);
+ method public byte getByte(String, byte);
+ method public byte[]? getByteArray(String);
+ method public double getDouble(String, double);
+ method public double[]? getDoubleArray(String);
+ method public float getFloat(String, float);
+ method public float[]? getFloatArray(String);
+ method public int getInt(String, int);
+ method public int[]? getIntArray(String);
+ method public java.util.Map<java.lang.String!,java.lang.Object!> getKeyValueMap();
+ method public long getLong(String, long);
+ method public long[]? getLongArray(String);
+ method public String? getString(String);
+ method public String![]? getStringArray(String);
+ method public <T> boolean hasKeyWithValueOfType(String, Class<T!>);
+ method public byte[] toByteArray();
+ field public static final androidx.work.Data EMPTY;
+ field public static final int MAX_DATA_BYTES = 10240; // 0x2800
+ }
+
+ public static final class Data.Builder {
+ ctor public Data.Builder();
+ method public androidx.work.Data build();
+ method public androidx.work.Data.Builder putAll(androidx.work.Data);
+ method public androidx.work.Data.Builder putAll(java.util.Map<java.lang.String!,java.lang.Object!>);
+ method public androidx.work.Data.Builder putBoolean(String, boolean);
+ method public androidx.work.Data.Builder putBooleanArray(String, boolean[]);
+ method public androidx.work.Data.Builder putByte(String, byte);
+ method public androidx.work.Data.Builder putByteArray(String, byte[]);
+ method public androidx.work.Data.Builder putDouble(String, double);
+ method public androidx.work.Data.Builder putDoubleArray(String, double[]);
+ method public androidx.work.Data.Builder putFloat(String, float);
+ method public androidx.work.Data.Builder putFloatArray(String, float[]);
+ method public androidx.work.Data.Builder putInt(String, int);
+ method public androidx.work.Data.Builder putIntArray(String, int[]);
+ method public androidx.work.Data.Builder putLong(String, long);
+ method public androidx.work.Data.Builder putLongArray(String, long[]);
+ method public androidx.work.Data.Builder putString(String, String?);
+ method public androidx.work.Data.Builder putStringArray(String, String![]);
+ }
+
+ public class DelegatingWorkerFactory extends androidx.work.WorkerFactory {
+ ctor public DelegatingWorkerFactory();
+ method public final void addFactory(androidx.work.WorkerFactory);
+ method public final androidx.work.ListenableWorker? createWorker(android.content.Context, String, androidx.work.WorkerParameters);
+ }
+
+ public enum ExistingPeriodicWorkPolicy {
+ method public static androidx.work.ExistingPeriodicWorkPolicy valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.ExistingPeriodicWorkPolicy[] values();
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy CANCEL_AND_REENQUEUE;
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy KEEP;
+ enum_constant @Deprecated public static final androidx.work.ExistingPeriodicWorkPolicy REPLACE;
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy UPDATE;
+ }
+
+ public enum ExistingWorkPolicy {
+ method public static androidx.work.ExistingWorkPolicy valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.ExistingWorkPolicy[] values();
+ enum_constant public static final androidx.work.ExistingWorkPolicy APPEND;
+ enum_constant public static final androidx.work.ExistingWorkPolicy APPEND_OR_REPLACE;
+ enum_constant public static final androidx.work.ExistingWorkPolicy KEEP;
+ enum_constant public static final androidx.work.ExistingWorkPolicy REPLACE;
+ }
+
+ public final class ForegroundInfo {
+ ctor public ForegroundInfo(int, android.app.Notification);
+ ctor public ForegroundInfo(int, android.app.Notification, int);
+ method public int getForegroundServiceType();
+ method public android.app.Notification getNotification();
+ method public int getNotificationId();
+ }
+
+ public interface ForegroundUpdater {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setForegroundAsync(android.content.Context, java.util.UUID, androidx.work.ForegroundInfo);
+ }
+
+ public interface InitializationExceptionHandler {
+ method public void handleException(Throwable);
+ }
+
+ public abstract class InputMerger {
+ ctor public InputMerger();
+ method public abstract androidx.work.Data merge(java.util.List<androidx.work.Data!>);
+ }
+
+ public abstract class InputMergerFactory {
+ ctor public InputMergerFactory();
+ method public abstract androidx.work.InputMerger? createInputMerger(String);
+ }
+
+ public abstract class ListenableWorker {
+ ctor public ListenableWorker(android.content.Context, androidx.work.WorkerParameters);
+ method public final android.content.Context getApplicationContext();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.work.ForegroundInfo!> getForegroundInfoAsync();
+ method public final java.util.UUID getId();
+ method public final androidx.work.Data getInputData();
+ method @RequiresApi(28) public final android.net.Network? getNetwork();
+ method @IntRange(from=0) public final int getRunAttemptCount();
+ method public final java.util.Set<java.lang.String!> getTags();
+ method @RequiresApi(24) public final java.util.List<java.lang.String!> getTriggeredContentAuthorities();
+ method @RequiresApi(24) public final java.util.List<android.net.Uri!> getTriggeredContentUris();
+ method public final boolean isStopped();
+ method public void onStopped();
+ method public final com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setForegroundAsync(androidx.work.ForegroundInfo);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setProgressAsync(androidx.work.Data);
+ method @MainThread public abstract com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ }
+
+ public abstract static class ListenableWorker.Result {
+ method public static androidx.work.ListenableWorker.Result failure();
+ method public static androidx.work.ListenableWorker.Result failure(androidx.work.Data);
+ method public abstract androidx.work.Data getOutputData();
+ method public static androidx.work.ListenableWorker.Result retry();
+ method public static androidx.work.ListenableWorker.Result success();
+ method public static androidx.work.ListenableWorker.Result success(androidx.work.Data);
+ }
+
+ public enum NetworkType {
+ method public static androidx.work.NetworkType valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.NetworkType[] values();
+ enum_constant public static final androidx.work.NetworkType CONNECTED;
+ enum_constant public static final androidx.work.NetworkType METERED;
+ enum_constant public static final androidx.work.NetworkType NOT_REQUIRED;
+ enum_constant public static final androidx.work.NetworkType NOT_ROAMING;
+ enum_constant @RequiresApi(30) public static final androidx.work.NetworkType TEMPORARILY_UNMETERED;
+ enum_constant public static final androidx.work.NetworkType UNMETERED;
+ }
+
+ public final class OneTimeWorkRequest extends androidx.work.WorkRequest {
+ method public static androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker> workerClass);
+ method public static java.util.List<androidx.work.OneTimeWorkRequest> from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>> workerClasses);
+ field public static final androidx.work.OneTimeWorkRequest.Companion Companion;
+ }
+
+ public static final class OneTimeWorkRequest.Builder extends androidx.work.WorkRequest.Builder<androidx.work.OneTimeWorkRequest.Builder,androidx.work.OneTimeWorkRequest> {
+ ctor public OneTimeWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass);
+ method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.InputMerger> inputMerger);
+ }
+
+ public static final class OneTimeWorkRequest.Companion {
+ method public androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker> workerClass);
+ method public java.util.List<androidx.work.OneTimeWorkRequest> from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>> workerClasses);
+ }
+
+ public final class OneTimeWorkRequestKt {
+ method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.OneTimeWorkRequest.Builder! OneTimeWorkRequestBuilder();
+ method public static inline androidx.work.OneTimeWorkRequest.Builder setInputMerger(androidx.work.OneTimeWorkRequest.Builder, kotlin.reflect.KClass<? extends androidx.work.InputMerger> inputMerger);
+ }
+
+ public interface Operation {
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.work.Operation.State.SUCCESS!> getResult();
+ method public androidx.lifecycle.LiveData<androidx.work.Operation.State!> getState();
+ }
+
+ public abstract static class Operation.State {
+ }
+
+ public static final class Operation.State.FAILURE extends androidx.work.Operation.State {
+ ctor public Operation.State.FAILURE(Throwable);
+ method public Throwable getThrowable();
+ }
+
+ public static final class Operation.State.IN_PROGRESS extends androidx.work.Operation.State {
+ }
+
+ public static final class Operation.State.SUCCESS extends androidx.work.Operation.State {
+ }
+
+ public enum OutOfQuotaPolicy {
+ method public static androidx.work.OutOfQuotaPolicy valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.OutOfQuotaPolicy[] values();
+ enum_constant public static final androidx.work.OutOfQuotaPolicy DROP_WORK_REQUEST;
+ enum_constant public static final androidx.work.OutOfQuotaPolicy RUN_AS_NON_EXPEDITED_WORK_REQUEST;
+ }
+
+ public final class OverwritingInputMerger extends androidx.work.InputMerger {
+ ctor public OverwritingInputMerger();
+ method public androidx.work.Data merge(java.util.List<androidx.work.Data!>);
+ }
+
+ public final class PeriodicWorkRequest extends androidx.work.WorkRequest {
+ field public static final androidx.work.PeriodicWorkRequest.Companion Companion;
+ field public static final long MIN_PERIODIC_FLEX_MILLIS = 300000L; // 0x493e0L
+ field public static final long MIN_PERIODIC_INTERVAL_MILLIS = 900000L; // 0xdbba0L
+ }
+
+ public static final class PeriodicWorkRequest.Builder extends androidx.work.WorkRequest.Builder<androidx.work.PeriodicWorkRequest.Builder,androidx.work.PeriodicWorkRequest> {
+ ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
+ ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, java.time.Duration repeatInterval);
+ ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexInterval, java.util.concurrent.TimeUnit flexIntervalTimeUnit);
+ ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, java.time.Duration repeatInterval, java.time.Duration flexInterval);
+ }
+
+ public static final class PeriodicWorkRequest.Companion {
+ }
+
+ public final class PeriodicWorkRequestKt {
+ method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
+ method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval);
+ method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexTimeInterval, java.util.concurrent.TimeUnit flexTimeIntervalUnit);
+ method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval, java.time.Duration flexTimeInterval);
+ }
+
+ public interface ProgressUpdater {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> updateProgress(android.content.Context, java.util.UUID, androidx.work.Data);
+ }
+
+ public interface RunnableScheduler {
+ method public void cancel(Runnable);
+ method public void scheduleWithDelay(@IntRange(from=0) long, Runnable);
+ }
+
+ public interface SchedulingExceptionHandler {
+ method public void handleException(Throwable);
+ }
+
+ public abstract class WorkContinuation {
+ ctor public WorkContinuation();
+ method public static androidx.work.WorkContinuation combine(java.util.List<androidx.work.WorkContinuation!>);
+ method public abstract androidx.work.Operation enqueue();
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfos();
+ method public abstract androidx.lifecycle.LiveData<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosLiveData();
+ method public final androidx.work.WorkContinuation then(androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.WorkContinuation then(java.util.List<androidx.work.OneTimeWorkRequest!>);
+ }
+
+ public final class WorkInfo {
+ method public int getGeneration();
+ method public java.util.UUID getId();
+ method public androidx.work.Data getOutputData();
+ method public androidx.work.Data getProgress();
+ method @IntRange(from=0) public int getRunAttemptCount();
+ method public androidx.work.WorkInfo.State getState();
+ method public java.util.Set<java.lang.String!> getTags();
+ }
+
+ public enum WorkInfo.State {
+ method public boolean isFinished();
+ enum_constant public static final androidx.work.WorkInfo.State BLOCKED;
+ enum_constant public static final androidx.work.WorkInfo.State CANCELLED;
+ enum_constant public static final androidx.work.WorkInfo.State ENQUEUED;
+ enum_constant public static final androidx.work.WorkInfo.State FAILED;
+ enum_constant public static final androidx.work.WorkInfo.State RUNNING;
+ enum_constant public static final androidx.work.WorkInfo.State SUCCEEDED;
+ }
+
+ public abstract class WorkManager {
+ method public final androidx.work.WorkContinuation beginUniqueWork(String, androidx.work.ExistingWorkPolicy, androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.WorkContinuation beginUniqueWork(String, androidx.work.ExistingWorkPolicy, java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public final androidx.work.WorkContinuation beginWith(androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.WorkContinuation beginWith(java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public abstract androidx.work.Operation cancelAllWork();
+ method public abstract androidx.work.Operation cancelAllWorkByTag(String);
+ method public abstract androidx.work.Operation cancelUniqueWork(String);
+ method public abstract androidx.work.Operation cancelWorkById(java.util.UUID);
+ method public abstract android.app.PendingIntent createCancelPendingIntent(java.util.UUID);
+ method public final androidx.work.Operation enqueue(androidx.work.WorkRequest);
+ method public abstract androidx.work.Operation enqueue(java.util.List<? extends androidx.work.WorkRequest>);
+ method public abstract androidx.work.Operation enqueueUniquePeriodicWork(String, androidx.work.ExistingPeriodicWorkPolicy, androidx.work.PeriodicWorkRequest);
+ method public androidx.work.Operation enqueueUniqueWork(String, androidx.work.ExistingWorkPolicy, androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.Operation enqueueUniqueWork(String, androidx.work.ExistingWorkPolicy, java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public abstract androidx.work.Configuration getConfiguration();
+ method @Deprecated public static androidx.work.WorkManager getInstance();
+ method public static androidx.work.WorkManager getInstance(android.content.Context);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Long!> getLastCancelAllTimeMillis();
+ method public abstract androidx.lifecycle.LiveData<java.lang.Long!> getLastCancelAllTimeMillisLiveData();
+ method public abstract com.google.common.util.concurrent.ListenableFuture<androidx.work.WorkInfo!> getWorkInfoById(java.util.UUID);
+ method public abstract androidx.lifecycle.LiveData<androidx.work.WorkInfo!> getWorkInfoByIdLiveData(java.util.UUID);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfos(androidx.work.WorkQuery);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosByTag(String);
+ method public abstract androidx.lifecycle.LiveData<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosByTagLiveData(String);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosForUniqueWork(String);
+ method public abstract androidx.lifecycle.LiveData<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosForUniqueWorkLiveData(String);
+ method public abstract androidx.lifecycle.LiveData<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosLiveData(androidx.work.WorkQuery);
+ method public static void initialize(android.content.Context, androidx.work.Configuration);
+ method public static boolean isInitialized();
+ method public abstract androidx.work.Operation pruneWork();
+ method public abstract com.google.common.util.concurrent.ListenableFuture<androidx.work.WorkManager.UpdateResult!> updateWork(androidx.work.WorkRequest);
+ }
+
+ public enum WorkManager.UpdateResult {
+ enum_constant public static final androidx.work.WorkManager.UpdateResult APPLIED_FOR_NEXT_RUN;
+ enum_constant public static final androidx.work.WorkManager.UpdateResult APPLIED_IMMEDIATELY;
+ enum_constant public static final androidx.work.WorkManager.UpdateResult NOT_APPLIED;
+ }
+
+ public final class WorkManagerInitializer implements androidx.startup.Initializer<androidx.work.WorkManager> {
+ ctor public WorkManagerInitializer();
+ method public androidx.work.WorkManager create(android.content.Context);
+ method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>!> dependencies();
+ }
+
+ public final class WorkQuery {
+ method public static androidx.work.WorkQuery fromIds(java.util.List<java.util.UUID!>);
+ method public static androidx.work.WorkQuery fromIds(java.util.UUID!...);
+ method public static androidx.work.WorkQuery fromStates(java.util.List<androidx.work.WorkInfo.State!>);
+ method public static androidx.work.WorkQuery fromStates(androidx.work.WorkInfo.State!...);
+ method public static androidx.work.WorkQuery fromTags(java.util.List<java.lang.String!>);
+ method public static androidx.work.WorkQuery fromTags(java.lang.String!...);
+ method public static androidx.work.WorkQuery fromUniqueWorkNames(java.lang.String!...);
+ method public static androidx.work.WorkQuery fromUniqueWorkNames(java.util.List<java.lang.String!>);
+ method public java.util.List<java.util.UUID!> getIds();
+ method public java.util.List<androidx.work.WorkInfo.State!> getStates();
+ method public java.util.List<java.lang.String!> getTags();
+ method public java.util.List<java.lang.String!> getUniqueWorkNames();
+ }
+
+ public static final class WorkQuery.Builder {
+ method public androidx.work.WorkQuery.Builder addIds(java.util.List<java.util.UUID!>);
+ method public androidx.work.WorkQuery.Builder addStates(java.util.List<androidx.work.WorkInfo.State!>);
+ method public androidx.work.WorkQuery.Builder addTags(java.util.List<java.lang.String!>);
+ method public androidx.work.WorkQuery.Builder addUniqueWorkNames(java.util.List<java.lang.String!>);
+ method public androidx.work.WorkQuery build();
+ method public static androidx.work.WorkQuery.Builder fromIds(java.util.List<java.util.UUID!>);
+ method public static androidx.work.WorkQuery.Builder fromStates(java.util.List<androidx.work.WorkInfo.State!>);
+ method public static androidx.work.WorkQuery.Builder fromTags(java.util.List<java.lang.String!>);
+ method public static androidx.work.WorkQuery.Builder fromUniqueWorkNames(java.util.List<java.lang.String!>);
+ }
+
+ public abstract class WorkRequest {
+ method public java.util.UUID getId();
+ property public java.util.UUID id;
+ field public static final androidx.work.WorkRequest.Companion Companion;
+ field public static final long DEFAULT_BACKOFF_DELAY_MILLIS = 30000L; // 0x7530L
+ field public static final long MAX_BACKOFF_MILLIS = 18000000L; // 0x112a880L
+ field public static final long MIN_BACKOFF_MILLIS = 10000L; // 0x2710L
+ }
+
+ public abstract static class WorkRequest.Builder<B extends androidx.work.WorkRequest.Builder<B, ?>, W extends androidx.work.WorkRequest> {
+ method public final B addTag(String tag);
+ method public final W build();
+ method public final B keepResultsForAtLeast(long duration, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration duration);
+ method public final B setBackoffCriteria(androidx.work.BackoffPolicy backoffPolicy, long backoffDelay, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy backoffPolicy, java.time.Duration duration);
+ method public final B setConstraints(androidx.work.Constraints constraints);
+ method public B setExpedited(androidx.work.OutOfQuotaPolicy policy);
+ method public final B setId(java.util.UUID id);
+ method public B setInitialDelay(long duration, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public B setInitialDelay(java.time.Duration duration);
+ method public final B setInputData(androidx.work.Data inputData);
+ }
+
+ public static final class WorkRequest.Companion {
+ }
+
+ public abstract class Worker extends androidx.work.ListenableWorker {
+ ctor public Worker(android.content.Context, androidx.work.WorkerParameters);
+ method @WorkerThread public abstract androidx.work.ListenableWorker.Result doWork();
+ method @WorkerThread public androidx.work.ForegroundInfo getForegroundInfo();
+ method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ }
+
+ public abstract class WorkerFactory {
+ ctor public WorkerFactory();
+ method public abstract androidx.work.ListenableWorker? createWorker(android.content.Context, String, androidx.work.WorkerParameters);
+ }
+
+ public final class WorkerParameters {
+ method @IntRange(from=0) public int getGeneration();
+ method public java.util.UUID getId();
+ method public androidx.work.Data getInputData();
+ method @RequiresApi(28) public android.net.Network? getNetwork();
+ method @IntRange(from=0) public int getRunAttemptCount();
+ method public java.util.Set<java.lang.String!> getTags();
+ method @RequiresApi(24) public java.util.List<java.lang.String!> getTriggeredContentAuthorities();
+ method @RequiresApi(24) public java.util.List<android.net.Uri!> getTriggeredContentUris();
+ }
+
+}
+
+package androidx.work.multiprocess {
+
+ public abstract class RemoteWorkContinuation {
+ method public static androidx.work.multiprocess.RemoteWorkContinuation combine(java.util.List<androidx.work.multiprocess.RemoteWorkContinuation!>);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueue();
+ method public final androidx.work.multiprocess.RemoteWorkContinuation then(androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.multiprocess.RemoteWorkContinuation then(java.util.List<androidx.work.OneTimeWorkRequest!>);
+ }
+
+ public abstract class RemoteWorkManager {
+ method public final androidx.work.multiprocess.RemoteWorkContinuation beginUniqueWork(String, androidx.work.ExistingWorkPolicy, androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.multiprocess.RemoteWorkContinuation beginUniqueWork(String, androidx.work.ExistingWorkPolicy, java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public final androidx.work.multiprocess.RemoteWorkContinuation beginWith(androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.multiprocess.RemoteWorkContinuation beginWith(java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelAllWork();
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelAllWorkByTag(String);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelUniqueWork(String);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelWorkById(java.util.UUID);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueue(androidx.work.WorkRequest);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueue(java.util.List<androidx.work.WorkRequest!>);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueueUniquePeriodicWork(String, androidx.work.ExistingPeriodicWorkPolicy, androidx.work.PeriodicWorkRequest);
+ method public final com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueueUniqueWork(String, androidx.work.ExistingWorkPolicy, androidx.work.OneTimeWorkRequest);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueueUniqueWork(String, androidx.work.ExistingWorkPolicy, java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public static androidx.work.multiprocess.RemoteWorkManager getInstance(android.content.Context);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfos(androidx.work.WorkQuery);
+ }
+
+}
+
diff --git a/work/work-runtime/api/res-2.8.0-beta01.txt b/work/work-runtime/api/res-2.8.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/work/work-runtime/api/res-2.8.0-beta01.txt
diff --git a/work/work-runtime/api/restricted_2.8.0-beta01.txt b/work/work-runtime/api/restricted_2.8.0-beta01.txt
new file mode 100644
index 0000000..4519d02
--- /dev/null
+++ b/work/work-runtime/api/restricted_2.8.0-beta01.txt
@@ -0,0 +1,499 @@
+// Signature format: 4.0
+package androidx.work {
+
+ public final class ArrayCreatingInputMerger extends androidx.work.InputMerger {
+ ctor public ArrayCreatingInputMerger();
+ method public androidx.work.Data merge(java.util.List<androidx.work.Data> inputs);
+ }
+
+ public enum BackoffPolicy {
+ method public static androidx.work.BackoffPolicy valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.BackoffPolicy[] values();
+ enum_constant public static final androidx.work.BackoffPolicy EXPONENTIAL;
+ enum_constant public static final androidx.work.BackoffPolicy LINEAR;
+ }
+
+ public final class Configuration {
+ method public String? getDefaultProcessName();
+ method public java.util.concurrent.Executor getExecutor();
+ method public androidx.work.InitializationExceptionHandler? getInitializationExceptionHandler();
+ method public androidx.work.InputMergerFactory getInputMergerFactory();
+ method public int getMaxJobSchedulerId();
+ method public int getMinJobSchedulerId();
+ method public androidx.work.RunnableScheduler getRunnableScheduler();
+ method public androidx.work.SchedulingExceptionHandler? getSchedulingExceptionHandler();
+ method public java.util.concurrent.Executor getTaskExecutor();
+ method public androidx.work.WorkerFactory getWorkerFactory();
+ field public static final int MIN_SCHEDULER_LIMIT = 20; // 0x14
+ }
+
+ public static final class Configuration.Builder {
+ ctor public Configuration.Builder();
+ method public androidx.work.Configuration build();
+ method public androidx.work.Configuration.Builder setDefaultProcessName(String);
+ method public androidx.work.Configuration.Builder setExecutor(java.util.concurrent.Executor);
+ method public androidx.work.Configuration.Builder setInitializationExceptionHandler(androidx.work.InitializationExceptionHandler);
+ method public androidx.work.Configuration.Builder setInputMergerFactory(androidx.work.InputMergerFactory);
+ method public androidx.work.Configuration.Builder setJobSchedulerJobIdRange(int, int);
+ method public androidx.work.Configuration.Builder setMaxSchedulerLimit(int);
+ method public androidx.work.Configuration.Builder setMinimumLoggingLevel(int);
+ method public androidx.work.Configuration.Builder setRunnableScheduler(androidx.work.RunnableScheduler);
+ method public androidx.work.Configuration.Builder setSchedulingExceptionHandler(androidx.work.SchedulingExceptionHandler);
+ method public androidx.work.Configuration.Builder setTaskExecutor(java.util.concurrent.Executor);
+ method public androidx.work.Configuration.Builder setWorkerFactory(androidx.work.WorkerFactory);
+ }
+
+ public static interface Configuration.Provider {
+ method public androidx.work.Configuration getWorkManagerConfiguration();
+ }
+
+ public final class Constraints {
+ ctor public Constraints(optional @androidx.room.ColumnInfo(name="required_network_type") androidx.work.NetworkType requiredNetworkType, optional @androidx.room.ColumnInfo(name="requires_charging") boolean requiresCharging, optional @androidx.room.ColumnInfo(name="requires_device_idle") boolean requiresDeviceIdle, optional @androidx.room.ColumnInfo(name="requires_battery_not_low") boolean requiresBatteryNotLow, optional @androidx.room.ColumnInfo(name="requires_storage_not_low") boolean requiresStorageNotLow, optional @androidx.room.ColumnInfo(name="trigger_content_update_delay") long contentTriggerUpdateDelayMillis, optional @androidx.room.ColumnInfo(name="trigger_max_content_delay") long contentTriggerMaxDelayMillis, optional @androidx.room.ColumnInfo(name="content_uri_triggers") java.util.Set<androidx.work.Constraints.ContentUriTrigger> contentUriTriggers);
+ ctor public Constraints(androidx.work.Constraints other);
+ method public long getContentTriggerMaxDelayMillis();
+ method public long getContentTriggerUpdateDelayMillis();
+ method public java.util.Set<androidx.work.Constraints.ContentUriTrigger> getContentUriTriggers();
+ method public androidx.work.NetworkType getRequiredNetworkType();
+ method public boolean requiresBatteryNotLow();
+ method public boolean requiresCharging();
+ method @RequiresApi(23) public boolean requiresDeviceIdle();
+ method public boolean requiresStorageNotLow();
+ property public final long contentTriggerMaxDelayMillis;
+ property public final long contentTriggerUpdateDelayMillis;
+ property public final java.util.Set<androidx.work.Constraints.ContentUriTrigger> contentUriTriggers;
+ property public final androidx.work.NetworkType requiredNetworkType;
+ field public static final androidx.work.Constraints.Companion Companion;
+ field public static final androidx.work.Constraints NONE;
+ }
+
+ public static final class Constraints.Builder {
+ ctor public Constraints.Builder();
+ method @RequiresApi(24) public androidx.work.Constraints.Builder addContentUriTrigger(android.net.Uri uri, boolean triggerForDescendants);
+ method public androidx.work.Constraints build();
+ method public androidx.work.Constraints.Builder setRequiredNetworkType(androidx.work.NetworkType networkType);
+ method public androidx.work.Constraints.Builder setRequiresBatteryNotLow(boolean requiresBatteryNotLow);
+ method public androidx.work.Constraints.Builder setRequiresCharging(boolean requiresCharging);
+ method @RequiresApi(23) public androidx.work.Constraints.Builder setRequiresDeviceIdle(boolean requiresDeviceIdle);
+ method public androidx.work.Constraints.Builder setRequiresStorageNotLow(boolean requiresStorageNotLow);
+ method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(long duration, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentMaxDelay(java.time.Duration duration);
+ method @RequiresApi(24) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(long duration, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public androidx.work.Constraints.Builder setTriggerContentUpdateDelay(java.time.Duration duration);
+ }
+
+ public static final class Constraints.Companion {
+ }
+
+ public static final class Constraints.ContentUriTrigger {
+ ctor public Constraints.ContentUriTrigger(android.net.Uri uri, boolean isTriggeredForDescendants);
+ method public android.net.Uri getUri();
+ method public boolean isTriggeredForDescendants();
+ property public final boolean isTriggeredForDescendants;
+ property public final android.net.Uri uri;
+ }
+
+ public final class Data {
+ ctor public Data(androidx.work.Data);
+ method @androidx.room.TypeConverter public static androidx.work.Data fromByteArray(byte[]);
+ method public boolean getBoolean(String, boolean);
+ method public boolean[]? getBooleanArray(String);
+ method public byte getByte(String, byte);
+ method public byte[]? getByteArray(String);
+ method public double getDouble(String, double);
+ method public double[]? getDoubleArray(String);
+ method public float getFloat(String, float);
+ method public float[]? getFloatArray(String);
+ method public int getInt(String, int);
+ method public int[]? getIntArray(String);
+ method public java.util.Map<java.lang.String!,java.lang.Object!> getKeyValueMap();
+ method public long getLong(String, long);
+ method public long[]? getLongArray(String);
+ method public String? getString(String);
+ method public String![]? getStringArray(String);
+ method public <T> boolean hasKeyWithValueOfType(String, Class<T!>);
+ method public byte[] toByteArray();
+ field public static final androidx.work.Data EMPTY;
+ field public static final int MAX_DATA_BYTES = 10240; // 0x2800
+ }
+
+ public static final class Data.Builder {
+ ctor public Data.Builder();
+ method public androidx.work.Data build();
+ method public androidx.work.Data.Builder putAll(androidx.work.Data);
+ method public androidx.work.Data.Builder putAll(java.util.Map<java.lang.String!,java.lang.Object!>);
+ method public androidx.work.Data.Builder putBoolean(String, boolean);
+ method public androidx.work.Data.Builder putBooleanArray(String, boolean[]);
+ method public androidx.work.Data.Builder putByte(String, byte);
+ method public androidx.work.Data.Builder putByteArray(String, byte[]);
+ method public androidx.work.Data.Builder putDouble(String, double);
+ method public androidx.work.Data.Builder putDoubleArray(String, double[]);
+ method public androidx.work.Data.Builder putFloat(String, float);
+ method public androidx.work.Data.Builder putFloatArray(String, float[]);
+ method public androidx.work.Data.Builder putInt(String, int);
+ method public androidx.work.Data.Builder putIntArray(String, int[]);
+ method public androidx.work.Data.Builder putLong(String, long);
+ method public androidx.work.Data.Builder putLongArray(String, long[]);
+ method public androidx.work.Data.Builder putString(String, String?);
+ method public androidx.work.Data.Builder putStringArray(String, String![]);
+ }
+
+ public class DelegatingWorkerFactory extends androidx.work.WorkerFactory {
+ ctor public DelegatingWorkerFactory();
+ method public final void addFactory(androidx.work.WorkerFactory);
+ method public final androidx.work.ListenableWorker? createWorker(android.content.Context, String, androidx.work.WorkerParameters);
+ }
+
+ public enum ExistingPeriodicWorkPolicy {
+ method public static androidx.work.ExistingPeriodicWorkPolicy valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.ExistingPeriodicWorkPolicy[] values();
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy CANCEL_AND_REENQUEUE;
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy KEEP;
+ enum_constant @Deprecated public static final androidx.work.ExistingPeriodicWorkPolicy REPLACE;
+ enum_constant public static final androidx.work.ExistingPeriodicWorkPolicy UPDATE;
+ }
+
+ public enum ExistingWorkPolicy {
+ method public static androidx.work.ExistingWorkPolicy valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.ExistingWorkPolicy[] values();
+ enum_constant public static final androidx.work.ExistingWorkPolicy APPEND;
+ enum_constant public static final androidx.work.ExistingWorkPolicy APPEND_OR_REPLACE;
+ enum_constant public static final androidx.work.ExistingWorkPolicy KEEP;
+ enum_constant public static final androidx.work.ExistingWorkPolicy REPLACE;
+ }
+
+ public final class ForegroundInfo {
+ ctor public ForegroundInfo(int, android.app.Notification);
+ ctor public ForegroundInfo(int, android.app.Notification, int);
+ method public int getForegroundServiceType();
+ method public android.app.Notification getNotification();
+ method public int getNotificationId();
+ }
+
+ public interface ForegroundUpdater {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setForegroundAsync(android.content.Context, java.util.UUID, androidx.work.ForegroundInfo);
+ }
+
+ public interface InitializationExceptionHandler {
+ method public void handleException(Throwable);
+ }
+
+ public abstract class InputMerger {
+ ctor public InputMerger();
+ method public abstract androidx.work.Data merge(java.util.List<androidx.work.Data!>);
+ }
+
+ public abstract class InputMergerFactory {
+ ctor public InputMergerFactory();
+ method public abstract androidx.work.InputMerger? createInputMerger(String);
+ }
+
+ public abstract class ListenableWorker {
+ ctor public ListenableWorker(android.content.Context, androidx.work.WorkerParameters);
+ method public final android.content.Context getApplicationContext();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.work.ForegroundInfo!> getForegroundInfoAsync();
+ method public final java.util.UUID getId();
+ method public final androidx.work.Data getInputData();
+ method @RequiresApi(28) public final android.net.Network? getNetwork();
+ method @IntRange(from=0) public final int getRunAttemptCount();
+ method public final java.util.Set<java.lang.String!> getTags();
+ method @RequiresApi(24) public final java.util.List<java.lang.String!> getTriggeredContentAuthorities();
+ method @RequiresApi(24) public final java.util.List<android.net.Uri!> getTriggeredContentUris();
+ method public final boolean isStopped();
+ method public void onStopped();
+ method public final com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setForegroundAsync(androidx.work.ForegroundInfo);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setProgressAsync(androidx.work.Data);
+ method @MainThread public abstract com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ }
+
+ public abstract static class ListenableWorker.Result {
+ method public static androidx.work.ListenableWorker.Result failure();
+ method public static androidx.work.ListenableWorker.Result failure(androidx.work.Data);
+ method public abstract androidx.work.Data getOutputData();
+ method public static androidx.work.ListenableWorker.Result retry();
+ method public static androidx.work.ListenableWorker.Result success();
+ method public static androidx.work.ListenableWorker.Result success(androidx.work.Data);
+ }
+
+ public enum NetworkType {
+ method public static androidx.work.NetworkType valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.NetworkType[] values();
+ enum_constant public static final androidx.work.NetworkType CONNECTED;
+ enum_constant public static final androidx.work.NetworkType METERED;
+ enum_constant public static final androidx.work.NetworkType NOT_REQUIRED;
+ enum_constant public static final androidx.work.NetworkType NOT_ROAMING;
+ enum_constant @RequiresApi(30) public static final androidx.work.NetworkType TEMPORARILY_UNMETERED;
+ enum_constant public static final androidx.work.NetworkType UNMETERED;
+ }
+
+ public final class OneTimeWorkRequest extends androidx.work.WorkRequest {
+ method public static androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker> workerClass);
+ method public static java.util.List<androidx.work.OneTimeWorkRequest> from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>> workerClasses);
+ field public static final androidx.work.OneTimeWorkRequest.Companion Companion;
+ }
+
+ public static final class OneTimeWorkRequest.Builder extends androidx.work.WorkRequest.Builder<androidx.work.OneTimeWorkRequest.Builder,androidx.work.OneTimeWorkRequest> {
+ ctor public OneTimeWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass);
+ method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.InputMerger> inputMerger);
+ }
+
+ public static final class OneTimeWorkRequest.Companion {
+ method public androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker> workerClass);
+ method public java.util.List<androidx.work.OneTimeWorkRequest> from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>> workerClasses);
+ }
+
+ public final class OneTimeWorkRequestKt {
+ method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.OneTimeWorkRequest.Builder! OneTimeWorkRequestBuilder();
+ method public static inline androidx.work.OneTimeWorkRequest.Builder setInputMerger(androidx.work.OneTimeWorkRequest.Builder, kotlin.reflect.KClass<? extends androidx.work.InputMerger> inputMerger);
+ }
+
+ public interface Operation {
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.work.Operation.State.SUCCESS!> getResult();
+ method public androidx.lifecycle.LiveData<androidx.work.Operation.State!> getState();
+ }
+
+ public abstract static class Operation.State {
+ }
+
+ public static final class Operation.State.FAILURE extends androidx.work.Operation.State {
+ ctor public Operation.State.FAILURE(Throwable);
+ method public Throwable getThrowable();
+ }
+
+ public static final class Operation.State.IN_PROGRESS extends androidx.work.Operation.State {
+ }
+
+ public static final class Operation.State.SUCCESS extends androidx.work.Operation.State {
+ }
+
+ public enum OutOfQuotaPolicy {
+ method public static androidx.work.OutOfQuotaPolicy valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.work.OutOfQuotaPolicy[] values();
+ enum_constant public static final androidx.work.OutOfQuotaPolicy DROP_WORK_REQUEST;
+ enum_constant public static final androidx.work.OutOfQuotaPolicy RUN_AS_NON_EXPEDITED_WORK_REQUEST;
+ }
+
+ public final class OverwritingInputMerger extends androidx.work.InputMerger {
+ ctor public OverwritingInputMerger();
+ method public androidx.work.Data merge(java.util.List<androidx.work.Data!>);
+ }
+
+ public final class PeriodicWorkRequest extends androidx.work.WorkRequest {
+ field public static final androidx.work.PeriodicWorkRequest.Companion Companion;
+ field public static final long MIN_PERIODIC_FLEX_MILLIS = 300000L; // 0x493e0L
+ field public static final long MIN_PERIODIC_INTERVAL_MILLIS = 900000L; // 0xdbba0L
+ }
+
+ public static final class PeriodicWorkRequest.Builder extends androidx.work.WorkRequest.Builder<androidx.work.PeriodicWorkRequest.Builder,androidx.work.PeriodicWorkRequest> {
+ ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
+ ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, java.time.Duration repeatInterval);
+ ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexInterval, java.util.concurrent.TimeUnit flexIntervalTimeUnit);
+ ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, java.time.Duration repeatInterval, java.time.Duration flexInterval);
+ }
+
+ public static final class PeriodicWorkRequest.Companion {
+ }
+
+ public final class PeriodicWorkRequestKt {
+ method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
+ method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval);
+ method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexTimeInterval, java.util.concurrent.TimeUnit flexTimeIntervalUnit);
+ method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval, java.time.Duration flexTimeInterval);
+ }
+
+ public interface ProgressUpdater {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> updateProgress(android.content.Context, java.util.UUID, androidx.work.Data);
+ }
+
+ public interface RunnableScheduler {
+ method public void cancel(Runnable);
+ method public void scheduleWithDelay(@IntRange(from=0) long, Runnable);
+ }
+
+ public interface SchedulingExceptionHandler {
+ method public void handleException(Throwable);
+ }
+
+ public abstract class WorkContinuation {
+ ctor public WorkContinuation();
+ method public static androidx.work.WorkContinuation combine(java.util.List<androidx.work.WorkContinuation!>);
+ method public abstract androidx.work.Operation enqueue();
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfos();
+ method public abstract androidx.lifecycle.LiveData<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosLiveData();
+ method public final androidx.work.WorkContinuation then(androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.WorkContinuation then(java.util.List<androidx.work.OneTimeWorkRequest!>);
+ }
+
+ public final class WorkInfo {
+ method public int getGeneration();
+ method public java.util.UUID getId();
+ method public androidx.work.Data getOutputData();
+ method public androidx.work.Data getProgress();
+ method @IntRange(from=0) public int getRunAttemptCount();
+ method public androidx.work.WorkInfo.State getState();
+ method public java.util.Set<java.lang.String!> getTags();
+ }
+
+ public enum WorkInfo.State {
+ method public boolean isFinished();
+ enum_constant public static final androidx.work.WorkInfo.State BLOCKED;
+ enum_constant public static final androidx.work.WorkInfo.State CANCELLED;
+ enum_constant public static final androidx.work.WorkInfo.State ENQUEUED;
+ enum_constant public static final androidx.work.WorkInfo.State FAILED;
+ enum_constant public static final androidx.work.WorkInfo.State RUNNING;
+ enum_constant public static final androidx.work.WorkInfo.State SUCCEEDED;
+ }
+
+ public abstract class WorkManager {
+ method public final androidx.work.WorkContinuation beginUniqueWork(String, androidx.work.ExistingWorkPolicy, androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.WorkContinuation beginUniqueWork(String, androidx.work.ExistingWorkPolicy, java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public final androidx.work.WorkContinuation beginWith(androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.WorkContinuation beginWith(java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public abstract androidx.work.Operation cancelAllWork();
+ method public abstract androidx.work.Operation cancelAllWorkByTag(String);
+ method public abstract androidx.work.Operation cancelUniqueWork(String);
+ method public abstract androidx.work.Operation cancelWorkById(java.util.UUID);
+ method public abstract android.app.PendingIntent createCancelPendingIntent(java.util.UUID);
+ method public final androidx.work.Operation enqueue(androidx.work.WorkRequest);
+ method public abstract androidx.work.Operation enqueue(java.util.List<? extends androidx.work.WorkRequest>);
+ method public abstract androidx.work.Operation enqueueUniquePeriodicWork(String, androidx.work.ExistingPeriodicWorkPolicy, androidx.work.PeriodicWorkRequest);
+ method public androidx.work.Operation enqueueUniqueWork(String, androidx.work.ExistingWorkPolicy, androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.Operation enqueueUniqueWork(String, androidx.work.ExistingWorkPolicy, java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public abstract androidx.work.Configuration getConfiguration();
+ method @Deprecated public static androidx.work.WorkManager getInstance();
+ method public static androidx.work.WorkManager getInstance(android.content.Context);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Long!> getLastCancelAllTimeMillis();
+ method public abstract androidx.lifecycle.LiveData<java.lang.Long!> getLastCancelAllTimeMillisLiveData();
+ method public abstract com.google.common.util.concurrent.ListenableFuture<androidx.work.WorkInfo!> getWorkInfoById(java.util.UUID);
+ method public abstract androidx.lifecycle.LiveData<androidx.work.WorkInfo!> getWorkInfoByIdLiveData(java.util.UUID);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfos(androidx.work.WorkQuery);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosByTag(String);
+ method public abstract androidx.lifecycle.LiveData<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosByTagLiveData(String);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosForUniqueWork(String);
+ method public abstract androidx.lifecycle.LiveData<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosForUniqueWorkLiveData(String);
+ method public abstract androidx.lifecycle.LiveData<java.util.List<androidx.work.WorkInfo!>!> getWorkInfosLiveData(androidx.work.WorkQuery);
+ method public static void initialize(android.content.Context, androidx.work.Configuration);
+ method public static boolean isInitialized();
+ method public abstract androidx.work.Operation pruneWork();
+ method public abstract com.google.common.util.concurrent.ListenableFuture<androidx.work.WorkManager.UpdateResult!> updateWork(androidx.work.WorkRequest);
+ }
+
+ public enum WorkManager.UpdateResult {
+ enum_constant public static final androidx.work.WorkManager.UpdateResult APPLIED_FOR_NEXT_RUN;
+ enum_constant public static final androidx.work.WorkManager.UpdateResult APPLIED_IMMEDIATELY;
+ enum_constant public static final androidx.work.WorkManager.UpdateResult NOT_APPLIED;
+ }
+
+ public final class WorkManagerInitializer implements androidx.startup.Initializer<androidx.work.WorkManager> {
+ ctor public WorkManagerInitializer();
+ method public androidx.work.WorkManager create(android.content.Context);
+ method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>!> dependencies();
+ }
+
+ public final class WorkQuery {
+ method public static androidx.work.WorkQuery fromIds(java.util.List<java.util.UUID!>);
+ method public static androidx.work.WorkQuery fromIds(java.util.UUID!...);
+ method public static androidx.work.WorkQuery fromStates(java.util.List<androidx.work.WorkInfo.State!>);
+ method public static androidx.work.WorkQuery fromStates(androidx.work.WorkInfo.State!...);
+ method public static androidx.work.WorkQuery fromTags(java.util.List<java.lang.String!>);
+ method public static androidx.work.WorkQuery fromTags(java.lang.String!...);
+ method public static androidx.work.WorkQuery fromUniqueWorkNames(java.lang.String!...);
+ method public static androidx.work.WorkQuery fromUniqueWorkNames(java.util.List<java.lang.String!>);
+ method public java.util.List<java.util.UUID!> getIds();
+ method public java.util.List<androidx.work.WorkInfo.State!> getStates();
+ method public java.util.List<java.lang.String!> getTags();
+ method public java.util.List<java.lang.String!> getUniqueWorkNames();
+ }
+
+ public static final class WorkQuery.Builder {
+ method public androidx.work.WorkQuery.Builder addIds(java.util.List<java.util.UUID!>);
+ method public androidx.work.WorkQuery.Builder addStates(java.util.List<androidx.work.WorkInfo.State!>);
+ method public androidx.work.WorkQuery.Builder addTags(java.util.List<java.lang.String!>);
+ method public androidx.work.WorkQuery.Builder addUniqueWorkNames(java.util.List<java.lang.String!>);
+ method public androidx.work.WorkQuery build();
+ method public static androidx.work.WorkQuery.Builder fromIds(java.util.List<java.util.UUID!>);
+ method public static androidx.work.WorkQuery.Builder fromStates(java.util.List<androidx.work.WorkInfo.State!>);
+ method public static androidx.work.WorkQuery.Builder fromTags(java.util.List<java.lang.String!>);
+ method public static androidx.work.WorkQuery.Builder fromUniqueWorkNames(java.util.List<java.lang.String!>);
+ }
+
+ public abstract class WorkRequest {
+ method public java.util.UUID getId();
+ property public java.util.UUID id;
+ field public static final androidx.work.WorkRequest.Companion Companion;
+ field public static final long DEFAULT_BACKOFF_DELAY_MILLIS = 30000L; // 0x7530L
+ field public static final long MAX_BACKOFF_MILLIS = 18000000L; // 0x112a880L
+ field public static final long MIN_BACKOFF_MILLIS = 10000L; // 0x2710L
+ }
+
+ public abstract static class WorkRequest.Builder<B extends androidx.work.WorkRequest.Builder<B, ?>, W extends androidx.work.WorkRequest> {
+ method public final B addTag(String tag);
+ method public final W build();
+ method public final B keepResultsForAtLeast(long duration, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration duration);
+ method public final B setBackoffCriteria(androidx.work.BackoffPolicy backoffPolicy, long backoffDelay, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy backoffPolicy, java.time.Duration duration);
+ method public final B setConstraints(androidx.work.Constraints constraints);
+ method public B setExpedited(androidx.work.OutOfQuotaPolicy policy);
+ method public final B setId(java.util.UUID id);
+ method public B setInitialDelay(long duration, java.util.concurrent.TimeUnit timeUnit);
+ method @RequiresApi(26) public B setInitialDelay(java.time.Duration duration);
+ method public final B setInputData(androidx.work.Data inputData);
+ }
+
+ public static final class WorkRequest.Companion {
+ }
+
+ public abstract class Worker extends androidx.work.ListenableWorker {
+ ctor public Worker(android.content.Context, androidx.work.WorkerParameters);
+ method @WorkerThread public abstract androidx.work.ListenableWorker.Result doWork();
+ method @WorkerThread public androidx.work.ForegroundInfo getForegroundInfo();
+ method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ }
+
+ public abstract class WorkerFactory {
+ ctor public WorkerFactory();
+ method public abstract androidx.work.ListenableWorker? createWorker(android.content.Context, String, androidx.work.WorkerParameters);
+ }
+
+ public final class WorkerParameters {
+ method @IntRange(from=0) public int getGeneration();
+ method public java.util.UUID getId();
+ method public androidx.work.Data getInputData();
+ method @RequiresApi(28) public android.net.Network? getNetwork();
+ method @IntRange(from=0) public int getRunAttemptCount();
+ method public java.util.Set<java.lang.String!> getTags();
+ method @RequiresApi(24) public java.util.List<java.lang.String!> getTriggeredContentAuthorities();
+ method @RequiresApi(24) public java.util.List<android.net.Uri!> getTriggeredContentUris();
+ }
+
+}
+
+package androidx.work.multiprocess {
+
+ public abstract class RemoteWorkContinuation {
+ method public static androidx.work.multiprocess.RemoteWorkContinuation combine(java.util.List<androidx.work.multiprocess.RemoteWorkContinuation!>);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueue();
+ method public final androidx.work.multiprocess.RemoteWorkContinuation then(androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.multiprocess.RemoteWorkContinuation then(java.util.List<androidx.work.OneTimeWorkRequest!>);
+ }
+
+ public abstract class RemoteWorkManager {
+ method public final androidx.work.multiprocess.RemoteWorkContinuation beginUniqueWork(String, androidx.work.ExistingWorkPolicy, androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.multiprocess.RemoteWorkContinuation beginUniqueWork(String, androidx.work.ExistingWorkPolicy, java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public final androidx.work.multiprocess.RemoteWorkContinuation beginWith(androidx.work.OneTimeWorkRequest);
+ method public abstract androidx.work.multiprocess.RemoteWorkContinuation beginWith(java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelAllWork();
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelAllWorkByTag(String);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelUniqueWork(String);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelWorkById(java.util.UUID);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueue(androidx.work.WorkRequest);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueue(java.util.List<androidx.work.WorkRequest!>);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueueUniquePeriodicWork(String, androidx.work.ExistingPeriodicWorkPolicy, androidx.work.PeriodicWorkRequest);
+ method public final com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueueUniqueWork(String, androidx.work.ExistingWorkPolicy, androidx.work.OneTimeWorkRequest);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enqueueUniqueWork(String, androidx.work.ExistingWorkPolicy, java.util.List<androidx.work.OneTimeWorkRequest!>);
+ method public static androidx.work.multiprocess.RemoteWorkManager getInstance(android.content.Context);
+ method public abstract com.google.common.util.concurrent.ListenableFuture<java.util.List<androidx.work.WorkInfo!>!> getWorkInfos(androidx.work.WorkQuery);
+ }
+
+}
+
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/StartStopToken.kt b/work/work-runtime/src/main/java/androidx/work/impl/StartStopToken.kt
index 034a5a45..f9c4245 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/StartStopToken.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/StartStopToken.kt
@@ -37,8 +37,7 @@
fun tokenFor(id: WorkGenerationalId): StartStopToken {
return synchronized(lock) {
- val startStopToken = StartStopToken(id)
- runs.getOrPut(id) { startStopToken }
+ runs.getOrPut(id) { StartStopToken(id) }
}
}
@@ -56,6 +55,10 @@
}
}
+ fun contains(id: WorkGenerationalId): Boolean {
+ return synchronized(lock) { runs.contains(id) }
+ }
+
fun tokenFor(spec: WorkSpec) = tokenFor(spec.generationalId())
fun remove(spec: WorkSpec) = remove(spec.generationalId())
}
\ 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 e1c9c42..656f129 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
@@ -124,6 +124,11 @@
Set<String> constrainedWorkSpecIds = new HashSet<>();
for (WorkSpec workSpec : workSpecs) {
+ // it doesn't help against races, but reduces useless load in the system
+ WorkGenerationalId id = generationalId(workSpec);
+ if (mStartStopTokens.contains(id)) {
+ continue;
+ }
long nextRunTime = workSpec.calculateNextRunTime();
long now = System.currentTimeMillis();
if (workSpec.state == WorkInfo.State.ENQUEUED) {
@@ -146,8 +151,11 @@
constrainedWorkSpecIds.add(workSpec.id);
}
} else {
- Logger.get().debug(TAG, "Starting work for " + workSpec.id);
- mWorkManagerImpl.startWork(mStartStopTokens.tokenFor(workSpec));
+ // it doesn't help against races, but reduces useless load in the system
+ if (!mStartStopTokens.contains(generationalId(workSpec))) {
+ Logger.get().debug(TAG, "Starting work for " + workSpec.id);
+ mWorkManagerImpl.startWork(mStartStopTokens.tokenFor(workSpec));
+ }
}
}
}
@@ -195,8 +203,11 @@
public void onAllConstraintsMet(@NonNull List<WorkSpec> workSpecs) {
for (WorkSpec workSpec : workSpecs) {
WorkGenerationalId id = generationalId(workSpec);
- Logger.get().debug(TAG, "Constraints met: Scheduling work ID " + id);
- mWorkManagerImpl.startWork(mStartStopTokens.tokenFor(id));
+ // it doesn't help against races, but reduces useless load in the system
+ if (!mStartStopTokens.contains(id)) {
+ Logger.get().debug(TAG, "Constraints met: Scheduling work ID " + id);
+ mWorkManagerImpl.startWork(mStartStopTokens.tokenFor(id));
+ }
}
}
diff --git a/work/work-rxjava2/api/2.8.0-beta01.txt b/work/work-rxjava2/api/2.8.0-beta01.txt
new file mode 100644
index 0000000..1cca40e
--- /dev/null
+++ b/work/work-rxjava2/api/2.8.0-beta01.txt
@@ -0,0 +1,16 @@
+// Signature format: 4.0
+package androidx.work {
+
+ public abstract class RxWorker extends androidx.work.ListenableWorker {
+ ctor public RxWorker(android.content.Context, androidx.work.WorkerParameters);
+ method @MainThread public abstract io.reactivex.Single<androidx.work.ListenableWorker.Result!> createWork();
+ method protected io.reactivex.Scheduler getBackgroundScheduler();
+ method public io.reactivex.Single<androidx.work.ForegroundInfo!> getForegroundInfo();
+ method public final io.reactivex.Completable setCompletableProgress(androidx.work.Data);
+ method public final io.reactivex.Completable setForeground(androidx.work.ForegroundInfo);
+ method @Deprecated public final io.reactivex.Single<java.lang.Void!> setProgress(androidx.work.Data);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ }
+
+}
+
diff --git a/work/work-rxjava2/api/public_plus_experimental_2.8.0-beta01.txt b/work/work-rxjava2/api/public_plus_experimental_2.8.0-beta01.txt
new file mode 100644
index 0000000..1cca40e
--- /dev/null
+++ b/work/work-rxjava2/api/public_plus_experimental_2.8.0-beta01.txt
@@ -0,0 +1,16 @@
+// Signature format: 4.0
+package androidx.work {
+
+ public abstract class RxWorker extends androidx.work.ListenableWorker {
+ ctor public RxWorker(android.content.Context, androidx.work.WorkerParameters);
+ method @MainThread public abstract io.reactivex.Single<androidx.work.ListenableWorker.Result!> createWork();
+ method protected io.reactivex.Scheduler getBackgroundScheduler();
+ method public io.reactivex.Single<androidx.work.ForegroundInfo!> getForegroundInfo();
+ method public final io.reactivex.Completable setCompletableProgress(androidx.work.Data);
+ method public final io.reactivex.Completable setForeground(androidx.work.ForegroundInfo);
+ method @Deprecated public final io.reactivex.Single<java.lang.Void!> setProgress(androidx.work.Data);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ }
+
+}
+
diff --git a/work/work-rxjava2/api/res-2.8.0-beta01.txt b/work/work-rxjava2/api/res-2.8.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/work/work-rxjava2/api/res-2.8.0-beta01.txt
diff --git a/work/work-rxjava2/api/restricted_2.8.0-beta01.txt b/work/work-rxjava2/api/restricted_2.8.0-beta01.txt
new file mode 100644
index 0000000..1cca40e
--- /dev/null
+++ b/work/work-rxjava2/api/restricted_2.8.0-beta01.txt
@@ -0,0 +1,16 @@
+// Signature format: 4.0
+package androidx.work {
+
+ public abstract class RxWorker extends androidx.work.ListenableWorker {
+ ctor public RxWorker(android.content.Context, androidx.work.WorkerParameters);
+ method @MainThread public abstract io.reactivex.Single<androidx.work.ListenableWorker.Result!> createWork();
+ method protected io.reactivex.Scheduler getBackgroundScheduler();
+ method public io.reactivex.Single<androidx.work.ForegroundInfo!> getForegroundInfo();
+ method public final io.reactivex.Completable setCompletableProgress(androidx.work.Data);
+ method public final io.reactivex.Completable setForeground(androidx.work.ForegroundInfo);
+ method @Deprecated public final io.reactivex.Single<java.lang.Void!> setProgress(androidx.work.Data);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ }
+
+}
+
diff --git a/work/work-rxjava3/api/2.8.0-beta01.txt b/work/work-rxjava3/api/2.8.0-beta01.txt
new file mode 100644
index 0000000..0983052
--- /dev/null
+++ b/work/work-rxjava3/api/2.8.0-beta01.txt
@@ -0,0 +1,15 @@
+// Signature format: 4.0
+package androidx.work.rxjava3 {
+
+ public abstract class RxWorker extends androidx.work.ListenableWorker {
+ ctor public RxWorker(android.content.Context, androidx.work.WorkerParameters);
+ method @MainThread public abstract io.reactivex.rxjava3.core.Single<androidx.work.ListenableWorker.Result!> createWork();
+ method protected io.reactivex.rxjava3.core.Scheduler getBackgroundScheduler();
+ method public io.reactivex.rxjava3.core.Single<androidx.work.ForegroundInfo!> getForegroundInfo();
+ method public final io.reactivex.rxjava3.core.Completable setCompletableProgress(androidx.work.Data);
+ method public final io.reactivex.rxjava3.core.Completable setForeground(androidx.work.ForegroundInfo);
+ method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ }
+
+}
+
diff --git a/work/work-rxjava3/api/public_plus_experimental_2.8.0-beta01.txt b/work/work-rxjava3/api/public_plus_experimental_2.8.0-beta01.txt
new file mode 100644
index 0000000..0983052
--- /dev/null
+++ b/work/work-rxjava3/api/public_plus_experimental_2.8.0-beta01.txt
@@ -0,0 +1,15 @@
+// Signature format: 4.0
+package androidx.work.rxjava3 {
+
+ public abstract class RxWorker extends androidx.work.ListenableWorker {
+ ctor public RxWorker(android.content.Context, androidx.work.WorkerParameters);
+ method @MainThread public abstract io.reactivex.rxjava3.core.Single<androidx.work.ListenableWorker.Result!> createWork();
+ method protected io.reactivex.rxjava3.core.Scheduler getBackgroundScheduler();
+ method public io.reactivex.rxjava3.core.Single<androidx.work.ForegroundInfo!> getForegroundInfo();
+ method public final io.reactivex.rxjava3.core.Completable setCompletableProgress(androidx.work.Data);
+ method public final io.reactivex.rxjava3.core.Completable setForeground(androidx.work.ForegroundInfo);
+ method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ }
+
+}
+
diff --git a/work/work-rxjava3/api/res-2.8.0-beta01.txt b/work/work-rxjava3/api/res-2.8.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/work/work-rxjava3/api/res-2.8.0-beta01.txt
diff --git a/work/work-rxjava3/api/restricted_2.8.0-beta01.txt b/work/work-rxjava3/api/restricted_2.8.0-beta01.txt
new file mode 100644
index 0000000..0983052
--- /dev/null
+++ b/work/work-rxjava3/api/restricted_2.8.0-beta01.txt
@@ -0,0 +1,15 @@
+// Signature format: 4.0
+package androidx.work.rxjava3 {
+
+ public abstract class RxWorker extends androidx.work.ListenableWorker {
+ ctor public RxWorker(android.content.Context, androidx.work.WorkerParameters);
+ method @MainThread public abstract io.reactivex.rxjava3.core.Single<androidx.work.ListenableWorker.Result!> createWork();
+ method protected io.reactivex.rxjava3.core.Scheduler getBackgroundScheduler();
+ method public io.reactivex.rxjava3.core.Single<androidx.work.ForegroundInfo!> getForegroundInfo();
+ method public final io.reactivex.rxjava3.core.Completable setCompletableProgress(androidx.work.Data);
+ method public final io.reactivex.rxjava3.core.Completable setForeground(androidx.work.ForegroundInfo);
+ method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
+ }
+
+}
+
diff --git a/work/work-testing/api/2.8.0-beta01.txt b/work/work-testing/api/2.8.0-beta01.txt
new file mode 100644
index 0000000..f3f3fe2
--- /dev/null
+++ b/work/work-testing/api/2.8.0-beta01.txt
@@ -0,0 +1,52 @@
+// Signature format: 4.0
+package androidx.work.testing {
+
+ public class SynchronousExecutor implements java.util.concurrent.Executor {
+ ctor public SynchronousExecutor();
+ method public void execute(Runnable);
+ }
+
+ public interface TestDriver {
+ method public void setAllConstraintsMet(java.util.UUID);
+ method public void setInitialDelayMet(java.util.UUID);
+ method public void setPeriodDelayMet(java.util.UUID);
+ }
+
+ public class TestListenableWorkerBuilder<W extends androidx.work.ListenableWorker> {
+ method public W build();
+ method public static androidx.work.testing.TestListenableWorkerBuilder<? extends androidx.work.ListenableWorker> from(android.content.Context, androidx.work.WorkRequest);
+ method public static <W extends androidx.work.ListenableWorker> androidx.work.testing.TestListenableWorkerBuilder<W!> from(android.content.Context, Class<W!>);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setForegroundUpdater(androidx.work.ForegroundUpdater);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setId(java.util.UUID);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setInputData(androidx.work.Data);
+ method @RequiresApi(28) public androidx.work.testing.TestListenableWorkerBuilder<W!> setNetwork(android.net.Network);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setProgressUpdater(androidx.work.ProgressUpdater);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setRunAttemptCount(int);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setTags(java.util.List<java.lang.String!>);
+ method @RequiresApi(24) public androidx.work.testing.TestListenableWorkerBuilder<W!> setTriggeredContentAuthorities(java.util.List<java.lang.String!>);
+ method @RequiresApi(24) public androidx.work.testing.TestListenableWorkerBuilder<W!> setTriggeredContentUris(java.util.List<android.net.Uri!>);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setWorkerFactory(androidx.work.WorkerFactory);
+ }
+
+ public final class TestListenableWorkerBuilderKt {
+ method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.testing.TestListenableWorkerBuilder<W>! TestListenableWorkerBuilder(android.content.Context context, optional androidx.work.Data inputData, optional java.util.List<? extends java.lang.String> tags, optional int runAttemptCount, optional java.util.List<? extends android.net.Uri> triggeredContentUris, optional java.util.List<? extends java.lang.String> triggeredContentAuthorities);
+ }
+
+ public class TestWorkerBuilder<W extends androidx.work.Worker> extends androidx.work.testing.TestListenableWorkerBuilder<W> {
+ method public static androidx.work.testing.TestWorkerBuilder<? extends androidx.work.Worker> from(android.content.Context, androidx.work.WorkRequest, java.util.concurrent.Executor);
+ method public static <W extends androidx.work.Worker> androidx.work.testing.TestWorkerBuilder<W!> from(android.content.Context, Class<W!>, java.util.concurrent.Executor);
+ }
+
+ public final class TestWorkerBuilderKt {
+ method public static inline <reified W extends androidx.work.Worker> androidx.work.testing.TestWorkerBuilder<W>! TestWorkerBuilder(android.content.Context context, java.util.concurrent.Executor executor, optional androidx.work.Data inputData, optional java.util.List<? extends java.lang.String> tags, optional int runAttemptCount, optional java.util.List<? extends android.net.Uri> triggeredContentUris, optional java.util.List<? extends java.lang.String> triggeredContentAuthorities);
+ }
+
+ public final class WorkManagerTestInitHelper {
+ method @Deprecated public static androidx.work.testing.TestDriver? getTestDriver();
+ 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);
+ }
+
+}
+
diff --git a/work/work-testing/api/public_plus_experimental_2.8.0-beta01.txt b/work/work-testing/api/public_plus_experimental_2.8.0-beta01.txt
new file mode 100644
index 0000000..f3f3fe2
--- /dev/null
+++ b/work/work-testing/api/public_plus_experimental_2.8.0-beta01.txt
@@ -0,0 +1,52 @@
+// Signature format: 4.0
+package androidx.work.testing {
+
+ public class SynchronousExecutor implements java.util.concurrent.Executor {
+ ctor public SynchronousExecutor();
+ method public void execute(Runnable);
+ }
+
+ public interface TestDriver {
+ method public void setAllConstraintsMet(java.util.UUID);
+ method public void setInitialDelayMet(java.util.UUID);
+ method public void setPeriodDelayMet(java.util.UUID);
+ }
+
+ public class TestListenableWorkerBuilder<W extends androidx.work.ListenableWorker> {
+ method public W build();
+ method public static androidx.work.testing.TestListenableWorkerBuilder<? extends androidx.work.ListenableWorker> from(android.content.Context, androidx.work.WorkRequest);
+ method public static <W extends androidx.work.ListenableWorker> androidx.work.testing.TestListenableWorkerBuilder<W!> from(android.content.Context, Class<W!>);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setForegroundUpdater(androidx.work.ForegroundUpdater);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setId(java.util.UUID);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setInputData(androidx.work.Data);
+ method @RequiresApi(28) public androidx.work.testing.TestListenableWorkerBuilder<W!> setNetwork(android.net.Network);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setProgressUpdater(androidx.work.ProgressUpdater);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setRunAttemptCount(int);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setTags(java.util.List<java.lang.String!>);
+ method @RequiresApi(24) public androidx.work.testing.TestListenableWorkerBuilder<W!> setTriggeredContentAuthorities(java.util.List<java.lang.String!>);
+ method @RequiresApi(24) public androidx.work.testing.TestListenableWorkerBuilder<W!> setTriggeredContentUris(java.util.List<android.net.Uri!>);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setWorkerFactory(androidx.work.WorkerFactory);
+ }
+
+ public final class TestListenableWorkerBuilderKt {
+ method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.testing.TestListenableWorkerBuilder<W>! TestListenableWorkerBuilder(android.content.Context context, optional androidx.work.Data inputData, optional java.util.List<? extends java.lang.String> tags, optional int runAttemptCount, optional java.util.List<? extends android.net.Uri> triggeredContentUris, optional java.util.List<? extends java.lang.String> triggeredContentAuthorities);
+ }
+
+ public class TestWorkerBuilder<W extends androidx.work.Worker> extends androidx.work.testing.TestListenableWorkerBuilder<W> {
+ method public static androidx.work.testing.TestWorkerBuilder<? extends androidx.work.Worker> from(android.content.Context, androidx.work.WorkRequest, java.util.concurrent.Executor);
+ method public static <W extends androidx.work.Worker> androidx.work.testing.TestWorkerBuilder<W!> from(android.content.Context, Class<W!>, java.util.concurrent.Executor);
+ }
+
+ public final class TestWorkerBuilderKt {
+ method public static inline <reified W extends androidx.work.Worker> androidx.work.testing.TestWorkerBuilder<W>! TestWorkerBuilder(android.content.Context context, java.util.concurrent.Executor executor, optional androidx.work.Data inputData, optional java.util.List<? extends java.lang.String> tags, optional int runAttemptCount, optional java.util.List<? extends android.net.Uri> triggeredContentUris, optional java.util.List<? extends java.lang.String> triggeredContentAuthorities);
+ }
+
+ public final class WorkManagerTestInitHelper {
+ method @Deprecated public static androidx.work.testing.TestDriver? getTestDriver();
+ 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);
+ }
+
+}
+
diff --git a/work/work-testing/api/res-2.8.0-beta01.txt b/work/work-testing/api/res-2.8.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/work/work-testing/api/res-2.8.0-beta01.txt
diff --git a/work/work-testing/api/restricted_2.8.0-beta01.txt b/work/work-testing/api/restricted_2.8.0-beta01.txt
new file mode 100644
index 0000000..f3f3fe2
--- /dev/null
+++ b/work/work-testing/api/restricted_2.8.0-beta01.txt
@@ -0,0 +1,52 @@
+// Signature format: 4.0
+package androidx.work.testing {
+
+ public class SynchronousExecutor implements java.util.concurrent.Executor {
+ ctor public SynchronousExecutor();
+ method public void execute(Runnable);
+ }
+
+ public interface TestDriver {
+ method public void setAllConstraintsMet(java.util.UUID);
+ method public void setInitialDelayMet(java.util.UUID);
+ method public void setPeriodDelayMet(java.util.UUID);
+ }
+
+ public class TestListenableWorkerBuilder<W extends androidx.work.ListenableWorker> {
+ method public W build();
+ method public static androidx.work.testing.TestListenableWorkerBuilder<? extends androidx.work.ListenableWorker> from(android.content.Context, androidx.work.WorkRequest);
+ method public static <W extends androidx.work.ListenableWorker> androidx.work.testing.TestListenableWorkerBuilder<W!> from(android.content.Context, Class<W!>);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setForegroundUpdater(androidx.work.ForegroundUpdater);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setId(java.util.UUID);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setInputData(androidx.work.Data);
+ method @RequiresApi(28) public androidx.work.testing.TestListenableWorkerBuilder<W!> setNetwork(android.net.Network);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setProgressUpdater(androidx.work.ProgressUpdater);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setRunAttemptCount(int);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setTags(java.util.List<java.lang.String!>);
+ method @RequiresApi(24) public androidx.work.testing.TestListenableWorkerBuilder<W!> setTriggeredContentAuthorities(java.util.List<java.lang.String!>);
+ method @RequiresApi(24) public androidx.work.testing.TestListenableWorkerBuilder<W!> setTriggeredContentUris(java.util.List<android.net.Uri!>);
+ method public androidx.work.testing.TestListenableWorkerBuilder<W!> setWorkerFactory(androidx.work.WorkerFactory);
+ }
+
+ public final class TestListenableWorkerBuilderKt {
+ method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.testing.TestListenableWorkerBuilder<W>! TestListenableWorkerBuilder(android.content.Context context, optional androidx.work.Data inputData, optional java.util.List<? extends java.lang.String> tags, optional int runAttemptCount, optional java.util.List<? extends android.net.Uri> triggeredContentUris, optional java.util.List<? extends java.lang.String> triggeredContentAuthorities);
+ }
+
+ public class TestWorkerBuilder<W extends androidx.work.Worker> extends androidx.work.testing.TestListenableWorkerBuilder<W> {
+ method public static androidx.work.testing.TestWorkerBuilder<? extends androidx.work.Worker> from(android.content.Context, androidx.work.WorkRequest, java.util.concurrent.Executor);
+ method public static <W extends androidx.work.Worker> androidx.work.testing.TestWorkerBuilder<W!> from(android.content.Context, Class<W!>, java.util.concurrent.Executor);
+ }
+
+ public final class TestWorkerBuilderKt {
+ method public static inline <reified W extends androidx.work.Worker> androidx.work.testing.TestWorkerBuilder<W>! TestWorkerBuilder(android.content.Context context, java.util.concurrent.Executor executor, optional androidx.work.Data inputData, optional java.util.List<? extends java.lang.String> tags, optional int runAttemptCount, optional java.util.List<? extends android.net.Uri> triggeredContentUris, optional java.util.List<? extends java.lang.String> triggeredContentAuthorities);
+ }
+
+ public final class WorkManagerTestInitHelper {
+ method @Deprecated public static androidx.work.testing.TestDriver? getTestDriver();
+ 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);
+ }
+
+}
+